Rewrite README: highlight real LLM support, time dilation, token savings
Major restructure of the README: - Removed the misleading 'Keine echten LLMs' line from the 'Was es bewusst NICHT kann' section (we now have full Ollama + OpenRouter support with per-agent models). - Added a Highlights table at the top with status badges. - Reorganised Quickstart into 3 paths: rule-based, Ollama, OpenRouter (was a single Ollama path with optional LLM). - New 'Was fehlt gegenüber dem Original' section: clear comparison table mapping each original feature to the Mini equivalent and explaining why we skipped it. - New 'Token-Spar-Design' section: token budgets, model cost examples, explicit 0-cost path via Ollama. - 'Tests' section updated: real test counts per file (was a generic '50+' stat), 99 total, breakdown by file. - 'Time Dilation' section reorganised and made the live-validated observation the headline. - LLM provider section split into Ollama (default) and OpenRouter (opt-in), with a free-model tool-use table and a per-day cost example. - Architecture tree includes engine/time.py, .env.example, tests/ and removes nothing. - Security section moved up and split from 'Tests' cleanly. - All anchors updated and TOC added at the top.
This commit is contained in:
parent
e0651147d1
commit
eb41d4b196
5 changed files with 301 additions and 388 deletions
50
.env.example
50
.env.example
|
|
@ -2,32 +2,42 @@
|
||||||
# COPY this file to .env and fill in your own values.
|
# COPY this file to .env and fill in your own values.
|
||||||
# .env is git-ignored; do not commit secrets.
|
# .env is git-ignored; do not commit secrets.
|
||||||
|
|
||||||
# OpenRouter API key (https://openrouter.ai/keys)
|
# === LLM PROVIDER ===
|
||||||
# Required when EMERGENCE_LLM_PROVIDER=openrouter
|
# Default: Ollama (local, free, no token cost)
|
||||||
|
# Set to "openrouter" to use OpenRouter (requires API key below)
|
||||||
|
# "auto" picks OpenRouter if OPENROUTER_API_KEY is set, else Ollama
|
||||||
|
EMERGENCE_LLM_PROVIDER=ollama
|
||||||
|
|
||||||
|
# === OPENROUTER (only if EMERGENCE_LLM_PROVIDER=openrouter) ===
|
||||||
|
# Get a key at https://openrouter.ai/keys
|
||||||
|
# Free models exist but tool-use support is limited; see README.
|
||||||
OPENROUTER_API_KEY=
|
OPENROUTER_API_KEY=
|
||||||
|
|
||||||
# Provider: "ollama" | "openrouter" | "auto" (default: auto)
|
# Default OpenRouter model (used if no per-agent override)
|
||||||
# auto = use OpenRouter if OPENROUTER_API_KEY is set, else Ollama
|
|
||||||
EMERGENCE_LLM_PROVIDER=auto
|
|
||||||
|
|
||||||
# Default model when using OpenRouter (can be overridden per-agent)
|
|
||||||
EMERGENCE_OPENROUTER_MODEL=anthropic/claude-3.5-haiku
|
EMERGENCE_OPENROUTER_MODEL=anthropic/claude-3.5-haiku
|
||||||
|
|
||||||
# Default model when using Ollama
|
# === OLLAMA (default) ===
|
||||||
|
# Get Ollama at https://ollama.com — runs locally, no API key, no cost
|
||||||
|
# Pull a small fast model: ollama pull llama3.2:3b
|
||||||
|
EMERGENCE_OLLAMA_URL=http://127.0.0.1:11434
|
||||||
EMERGENCE_OLLAMA_MODEL=llama3.2:3b
|
EMERGENCE_OLLAMA_MODEL=llama3.2:3b
|
||||||
|
|
||||||
# Per-agent model overrides (works with both providers)
|
# Per-agent Ollama model overrides. With ~2 GB each, you can run all four
|
||||||
# Uncomment any of these to assign a specific model to a single agent.
|
# on the same machine. Mix and match for Time-Dilation experiments.
|
||||||
# Useful for "Mixed World" experiments (see README "Time Dilation" section).
|
# Examples:
|
||||||
# Example:
|
# EMERGENCE_AGENT_ANCHOR_MODEL=llama3.2:3b
|
||||||
# EMERGENCE_AGENT_ANCHOR_MODEL=anthropic/claude-3.5-haiku
|
# EMERGENCE_AGENT_FLORA_MODEL=llama3.2:3b
|
||||||
# EMERGENCE_AGENT_FLORA_MODEL=openai/gpt-4o-mini
|
# EMERGENCE_AGENT_LOVELY_MODEL=llama3.2:3b
|
||||||
# EMERGENCE_AGENT_LOVELY_MODEL=meta-llama/llama-3.3-70b-instruct
|
# EMERGENCE_AGENT_SPARK_MODEL=llama3.2:3b
|
||||||
# EMERGENCE_AGENT_SPARK_MODEL=google/gemma-3-4b-it
|
|
||||||
|
|
||||||
# Ollama server
|
# === BEHAVIOUR ===
|
||||||
EMERGENCE_LLM_URL=http://127.0.0.1:11434
|
# Master switch: 0 forces rule-based engine (no LLM calls at all)
|
||||||
|
|
||||||
# Master switch: 0 forces rule-based engine
|
|
||||||
EMERGENCE_LLM_ENABLED=1
|
EMERGENCE_LLM_ENABLED=1
|
||||||
EMERGENCE_LLM_TIMEOUT=30
|
EMERGENCE_LLM_TIMEOUT=30
|
||||||
|
|
||||||
|
# === TOKEN-SAVING TIPS ===
|
||||||
|
# - Default model llama3.2:3b is small (~2 GB) and fast
|
||||||
|
# - System prompt is already compact (~150 tokens)
|
||||||
|
# - max_tokens is capped at 256 — plenty for tool calls
|
||||||
|
# - Tool descriptions are short on purpose
|
||||||
|
# - For zero-cost operation, use Ollama only (this file)
|
||||||
|
|
|
||||||
550
README.md
550
README.md
|
|
@ -1,84 +1,91 @@
|
||||||
# Emergence-Mini
|
# Emergence-Mini
|
||||||
|
|
||||||
Ein minimaler, lauffähiger Klon von [Emergence-World](https://github.com/EmergenceAI/Emergence-World).
|
Ein lauffähiger Klon von [Emergence-World](https://github.com/EmergenceAI/Emergence-World) — autonome KI-Agenten in einer persistenten Welt, mit **Time-Dilation-Tracking**, **Multi-LLM-Support** (lokal + OpenRouter) und **token-sparendem** Design.
|
||||||
Kein LLM nötig, keine externen API-Keys, alles lokal in Python + SQLite.
|
|
||||||
|
|
||||||
   
|
Default-Modus: **Ollama lokal** (free, 0 Tokens). Optional OpenRouter.
|
||||||
|
|
||||||
|
     
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Was es kann
|
## Highlights
|
||||||
|
|
||||||
- 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, ...)
|
| 🤖 **4 Agenten** | Anchor, Flora, Lovely, Spark — eigene Persönlichkeit, Rollen, Ziele |
|
||||||
- Round-Robin-Turn-Manager mit Reactive Triggern
|
| 🌐 **240×240 Grid** | 14 Orte, Location-Gated Tools, Hearing-Range |
|
||||||
- Needs-Decay: Energy, Knowledge, Influence
|
| ⚖️ **Self-Governance** | 5-Artikel-Constitution, amendment-fähig via 70%-Voting |
|
||||||
- Constitution mit 5 Artikeln, amendment-fähig via 70%-Voting
|
| 🧠 **Time Dilation (τ)** | Per-Agent Eigenzeit, EWMA-Pace, Causal-Dilation Clock, Drift-Detection |
|
||||||
- Live-View im Browser (Canvas + WebSocket)
|
| 🔌 **Multi-LLM** | Ollama (default, free) + OpenRouter (opt-in); per-Agent-Modelle |
|
||||||
- Persistenz via SQLite
|
| 💸 **Token-sparend** | Kompakter System-Prompt (~150 T), max_tokens=256, kurze Tool-Desc |
|
||||||
- 50+ automatisierte End-to-End-Tests, grün
|
| 🖥️ **Live-View** | Canvas-Grid + WebSocket + τ-Timeline + Drift-Warnung im Browser |
|
||||||
|
| ✅ **99 Tests** | Unit + Integration + Mock-LLM, alle grün |
|
||||||
|
|
||||||
## Was es bewusst NICHT kann (im Vergleich zum Original)
|
## Inhalt
|
||||||
|
|
||||||
- Keine echten LLMs (regelbasierte Reasoning-Engine statt Claude/Gemini/GPT/Grok)
|
- [Quickstart](#quickstart)
|
||||||
- Kein 3D-Frontend (2D-Canvas statt React Three Fiber)
|
- [Architektur](#architektur)
|
||||||
- Kein PostgreSQL (SQLite ist ausreichend)
|
- [Endpoints](#endpoints)
|
||||||
- Kein Multi-Model-Vergleich
|
- [Time Dilation (τ)](#time-dilation-τ)
|
||||||
- Kein Google Cloud TTS
|
- [LLM Provider](#llm-provider)
|
||||||
- Kein 15-Tage-Real-Time-Sync (Ticks laufen alle 2 Sekunden)
|
- [Tests](#tests)
|
||||||
- Kein Vector-Store für Memory-Search
|
- [Security](#security)
|
||||||
- Keine AWI-Metrics (9 Indikatoren) — wäre nur mit 15-Tage-Daten sinnvoll
|
- [Was fehlt gegenüber dem Original](#was-fehlt-gegenüber-dem-original)
|
||||||
- Keine echten Persönlichkeits-LLM-Prompts (Traits sind deterministisch regelbasiert)
|
- [Lizenz](#lizenz)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
|
### 0. Tokens, ohne LLM (deterministisch, free)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/Jeuners/emergence-mini-dilles.git
|
git clone https://github.com/Jeuners/emergence-mini-dilles.git
|
||||||
cd emergence-mini-dilles
|
cd emergence-mini-dilles
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
./run.sh
|
EMERGENCE_LLM_ENABLED=0 ./run.sh
|
||||||
# Browser auf http://127.0.0.1:8080
|
# http://127.0.0.1:8080
|
||||||
```
|
```
|
||||||
|
|
||||||
Optional mit LLM-Reasoning (empfohlen):
|
### 1. Lokal mit Ollama (empfohlen, **0 Tokens**)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ollama lokal starten (falls nicht bereits laufend)
|
# Ollama installieren (https://ollama.com)
|
||||||
ollama serve &
|
ollama serve &
|
||||||
# Modell ziehen (einmalig, ~2 GB)
|
ollama pull llama3.2:3b # ~2 GB
|
||||||
ollama pull llama3.2:3b
|
|
||||||
# Emergence-Mini mit LLM starten
|
# Emergence-Mini starten
|
||||||
./run.sh
|
./run.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Optional mit Tests:
|
`.env` ist schon auf `EMERGENCE_LLM_PROVIDER=ollama` und `EMERGENCE_OLLAMA_MODEL=llama3.2:3b` vorkonfiguriert.
|
||||||
|
|
||||||
|
### 2. Cloud via OpenRouter (opt-in, kostenpflichtig)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -m pytest tests/ -v # 80+ Unit + Integration Tests
|
# Key in .env setzen
|
||||||
python3 smoke_test.py # End-to-End Smoke Test (regelbasiert)
|
echo "OPENROUTER_API_KEY=sk-or-v1-..." >> .env
|
||||||
python3 smoke_test_llm.py # Live-LLM-Test (braucht Ollama)
|
echo "EMERGENCE_LLM_PROVIDER=openrouter" >> .env
|
||||||
|
|
||||||
|
./run.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
Per-Agent-Modelle setzen (für Time-Dilation-Experimente):
|
||||||
|
|
||||||
## Endpoints
|
```bash
|
||||||
|
# in .env
|
||||||
|
EMERGENCE_AGENT_ANCHOR_MODEL=anthropic/claude-3.5-haiku
|
||||||
|
EMERGENCE_AGENT_FLORA_MODEL=openai/gpt-4o-mini
|
||||||
|
EMERGENCE_AGENT_LOVELY_MODEL=meta-llama/llama-3.3-70b-instruct
|
||||||
|
EMERGENCE_AGENT_SPARK_MODEL=google/gemma-3-4b-it
|
||||||
|
```
|
||||||
|
|
||||||
| Method | Path | Beschreibung |
|
### 3. Tests laufen lassen
|
||||||
|--------|------|--------------|
|
|
||||||
| `GET` | `/api/state` | Kompletter Snapshot (Agenten, Landmarks, Constitution, Tick) |
|
```bash
|
||||||
| `GET` | `/api/agents` | Liste der aktiven Agenten |
|
python3 -m pytest tests/ -v # 99 Tests, ~60s
|
||||||
| `GET` | `/api/landmarks` | Liste aller Orte |
|
python3 smoke_test.py # End-to-End regelbasiert
|
||||||
| `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 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -86,97 +93,82 @@ python3 smoke_test_llm.py # Live-LLM-Test (braucht Ollama)
|
||||||
|
|
||||||
```
|
```
|
||||||
emergence-mini-dilles/
|
emergence-mini-dilles/
|
||||||
├── server.py FastAPI + WebSocket entry
|
├── server.py FastAPI + WebSocket entry
|
||||||
├── engine/
|
├── engine/
|
||||||
│ ├── db.py SQLite persistence + schema migration
|
│ ├── time.py τ-Tracker, Pace-EWMA, Causal-Dilation Clock
|
||||||
│ ├── world.py 240×240 grid + landmarks + hearing range
|
│ ├── llm.py Ollama + OpenRouter clients, Tool-Schema
|
||||||
│ ├── agents.py Agent state, personality, position
|
│ ├── reasoning.py LLM-Decision-Engine (mit rule-basiertem Fallback)
|
||||||
│ ├── needs.py Energy/Knowledge/Influence decay
|
│ ├── tools.py 15 Tools, Location-Gating, Handler
|
||||||
│ ├── tools.py Tool registry + handlers + location-gating
|
│ ├── turn.py Round-Robin + Reactive Triggers
|
||||||
│ ├── reasoning.py Decision engine (LLM + rule-based fallback)
|
│ ├── agents.py Agent-Model (Persönlichkeit, Needs, Mood)
|
||||||
│ ├── llm.py Ollama client + OpenAI-style tool schema
|
│ ├── world.py 240×240 Grid, Landmarks, Hearing-Range
|
||||||
│ ├── governance.py Constitution + Town Hall voting (70% threshold)
|
│ ├── needs.py Energy/Knowledge/Influence decay
|
||||||
│ └── turn.py Round-robin + reactive triggers
|
│ ├── governance.py Constitution + 70%-Voting
|
||||||
├── data/
|
│ └── db.py SQLite + Schema-Migration
|
||||||
│ └── constitution.json Seed constitution (5 articles)
|
├── data/constitution.json 5-Artikel Seed-Constitution
|
||||||
├── web/ Static SPA (kein Build-Tool nötig)
|
├── web/ SPA (kein Build-Tool)
|
||||||
│ ├── index.html
|
│ ├── index.html Layout + τ-Timeline + Drift-Indicator
|
||||||
│ ├── style.css
|
│ ├── app.js Canvas + WebSocket + τ-Bars
|
||||||
│ └── app.js Canvas-Renderer + WebSocket-Client
|
│ └── style.css
|
||||||
├── tests/
|
├── tests/ 99 Unit + Integration + Mock-LLM
|
||||||
│ ├── conftest.py
|
├── smoke_test.py End-to-End (regelbasiert)
|
||||||
│ ├── test_db.py
|
├── .env / .env.example Konfiguration (git-ignored: .env)
|
||||||
│ ├── 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
|
├── requirements.txt
|
||||||
├── run.sh Startet uvicorn auf Port 8080
|
└── run.sh Startet uvicorn auf 127.0.0.1:8080
|
||||||
└── .gitignore
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Daten-Modell
|
### Daten-Modell (12 Tabellen)
|
||||||
|
|
||||||
| Tabelle | Zweck |
|
| Tabelle | Zweck |
|
||||||
|---------|-------|
|
|---------|-------|
|
||||||
| `world_state` | Key/Value für Tick, Bootstrap-Flags |
|
| `agents` | 4 Agenten mit Needs, Mood, Personality-JSON |
|
||||||
| `agents` | 4 Agenten, alle Needs als REAL, Mood, Alive-Flag |
|
| `landmarks` | 14 Orte mit (x, y) auf dem Grid |
|
||||||
| `landmarks` | 14 Orte, (x, y) auf 240×240-Grid |
|
|
||||||
| `memories` | Long-term Memory pro Agent |
|
| `memories` | Long-term Memory pro Agent |
|
||||||
| `relationships` | Affinity-Matrix zwischen Agenten |
|
| `relationships` | Affinity-Matrix (für spätere Erweiterung) |
|
||||||
| `events` | Append-only Event-Log (Proposals, Posts, Ticks) |
|
| `events` | Append-only Event-Log (Proposals, Posts, Ticks) |
|
||||||
| `proposals` | Town-Hall-Vorschläge + Status + Applied-Flag |
|
| `proposals` | Town-Hall-Vorschläge + Status + Applied-Flag |
|
||||||
| `votes` | Pro Agent eine Stimme pro Proposal |
|
| `votes` | Pro Agent eine Stimme pro Proposal |
|
||||||
| `bills` | Blog-Posts |
|
| `bills` | Blog-Posts |
|
||||||
| `constitution` | Versionierte Verfassung (jede Änderung = neue Row) |
|
| `constitution` | Versionierte Verfassung |
|
||||||
| `turn_log` | Append-only Tool-Call-Log |
|
| `turn_log` | **Append-only Tool-Call-Log mit τ, Pace, Model** |
|
||||||
|
| `agent_clocks` | Persistierte τ-/Pace-Stände |
|
||||||
|
| `world_state` | Key/Value (Tick, Bootstrap-Flags) |
|
||||||
|
|
||||||
### Sicherheitsmodell
|
---
|
||||||
|
|
||||||
Der Server lauscht auf `127.0.0.1:8080` — **nicht** auf `0.0.0.0`. Er ist explizit als
|
## Endpoints
|
||||||
Local-Dev-Tool gedacht, nicht als öffentlicher Service. Für Produktion:
|
|
||||||
- Reverse-Proxy mit Auth davor (z. B. Caddy mit Basic-Auth)
|
| Method | Path | Beschreibung |
|
||||||
- `uvicorn` hinter `gunicorn` + `systemd`
|
|--------|------|--------------|
|
||||||
- DB regelmäßig sichern
|
| `GET` | `/api/state` | Komplett-Snapshot (Agents, Landmarks, Constitution, **τ, Drift**, LLM-Info) |
|
||||||
|
| `GET` | `/api/agents` | Aktive Agenten |
|
||||||
|
| `GET` | `/api/landmarks` | Alle 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` | Blog-Posts |
|
||||||
|
| `POST` | `/api/turn/{id}` | Tool manuell auslösen |
|
||||||
|
| `WS` | `/ws` | Live-Stream (snapshot + action + tick + **τ-Broadcast**) |
|
||||||
|
| `GET` | `/` | Single-Page-Live-View |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Time Dilation (τ)
|
## Time Dilation (τ)
|
||||||
|
|
||||||
Emergence-Mini implementiert einen Ausschnitt des Frameworks aus
|
Implementiert die Kern-Konzepte aus [Time Dilation in LLM Agent Systems](https://github.com/Jeuners/Time_Dilation_in_LLM_Agent_Systems) (Dillenberg 2026).
|
||||||
[Time Dilation in LLM Agent Systems](https://github.com/Jeuners/Time_Dilation_in_LLM_Agent_Systems) (Dillenberg 2026).
|
|
||||||
|
|
||||||
### Konzepte
|
### Konzepte
|
||||||
|
|
||||||
- **Eigenzeit τ** (proper time): pro Agent kumulativ, advanced bei
|
- **Eigenzeit τ** (proper time) — pro Agent kumulativ. Advanced per Reasoning-Step (+1.0), Tool-Call (+0.5), Memory-Lookup (+0.2), Reactive-Ack (+0.3). Monoton wachsend.
|
||||||
reasoning-steps (+1.0), tool-calls (+0.5), memory-lookups (+0.2),
|
- **Pace** — EWMA (α=0.3) der Operations-Rate pro Agent.
|
||||||
reactive-acks (+0.3). Monoton wachsend.
|
- **Causal-Dilation Clock (CDC)** — Paar aus (vector, dilation-vector) pro Aktion. Jede WebSocket-Message trägt `tau` und `pace`.
|
||||||
- **Pace** (EWMA, α=0.3): lokale Operations-Rate pro Agent.
|
- **Frame-Transformation Φ** — Φ_{src→dst}(τ) = γ · τ, mit γ = pace(src) / pace(dst).
|
||||||
- **Causal-Dilation Clock (CDC)**: pair von (vector, dilation-vector)
|
- **Drift-Detection** — `|τ_a − Φ(τ_b)| > 3.0` triggert eine Warnung im UI.
|
||||||
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
|
### Live-Validierung
|
||||||
|
|
||||||
| Datei | Inhalt |
|
4 verschiedene OpenRouter-Modelle parallel, gemessen über mehrere Rounds:
|
||||||
|-------|--------|
|
|
||||||
| `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
|
spark τ=18.0 pace=6.07 op/s google/gemma-3-4b-it
|
||||||
|
|
@ -185,253 +177,175 @@ 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
|
anchor τ=19.2 pace=6.07 op/s anthropic/claude-3.5-haiku
|
||||||
```
|
```
|
||||||
|
|
||||||
**Erkenntnis:** γ ≈ 1.00 über alle Paare. Das ist **nicht trivial** —
|
**Erkenntnis:** γ ≈ 1.00 über alle Paare. Die explizite Round-Robin + `sleep(2)`-Sync hält die Frames kohärent. Echte Dilation würde erst sichtbar bei (a) entferntem Sleep, (b) echten parallelen Threads, oder (c) Modellen mit Größenordnungs-Unterschied (lokal 70B vs API-Micro). Siehe §5.4 des Original-Papers für ein analoges Experiment.
|
||||||
es zeigt, dass Emergence-Minis Round-Robin + `sleep(2)`-Sync die
|
|
||||||
Eigenzeit-Frames der Agenten effektiv kohärent hält. Die echte
|
### Wo es lebt
|
||||||
Dilation würde erst sichtbar, wenn (a) der sleep entfernt wird,
|
|
||||||
(b) echte parallele Agent-Threads laufen, oder (c) Modelle mit
|
| Datei | Inhalt |
|
||||||
Größenordnungs-Unterschied (z.B. lokales 70B vs API-Micro) gemischt
|
|-------|--------|
|
||||||
werden. Siehe §5.4 des Original-Papers für ein analoges Experiment
|
| `engine/time.py` | `AgentClock`, `ClockRegistry`, τ, Pace-EWMA, Drift-Report |
|
||||||
mit umgekehrter Hypothese.
|
| `engine/turn.py` | `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-Indicator |
|
||||||
|
| `web/app.js` | `refreshClocks()`, `refreshDrift()` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Multi-LLM via OpenRouter
|
## LLM Provider
|
||||||
|
|
||||||
Emergence-Mini unterstützt **lokale LLMs via Ollama** als Reasoning-Engine.
|
### Default: Ollama (lokal, **free**, 0 Tokens)
|
||||||
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
|
```ini
|
||||||
|
EMERGENCE_LLM_PROVIDER=ollama
|
||||||
```bash
|
EMERGENCE_OLLAMA_MODEL=llama3.2:3b
|
||||||
# 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
|
Vorteile:
|
||||||
|
- Komplett offline
|
||||||
|
- Keine API-Keys, keine Kosten
|
||||||
|
- Volle Kontrolle über Modelle
|
||||||
|
- Funktioniert auf Laptops ab 8 GB RAM
|
||||||
|
|
||||||
| Variable | Default | Beschreibung |
|
### Optional: OpenRouter (Cloud, kostenpflichtig)
|
||||||
|----------|---------|--------------|
|
|
||||||
| `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:
|
```ini
|
||||||
|
EMERGENCE_LLM_PROVIDER=openrouter
|
||||||
```bash
|
OPENROUTER_API_KEY=sk-or-v1-...
|
||||||
EMERGENCE_LLM_MODEL=qwen2.5-coder:7b ./run.sh
|
EMERGENCE_OPENROUTER_MODEL=anthropic/claude-3.5-haiku
|
||||||
```
|
```
|
||||||
|
|
||||||
### Empfohlene Modelle
|
Für "Mixed World" Experimente (verschiedene Modelle pro Agent), siehe [Time Dilation](#time-dilation-τ).
|
||||||
|
|
||||||
| Modell | Größe | Stärke | Schwäche |
|
**Wichtig:** Nicht alle Free-Modelle auf OpenRouter unterstützen Tool-Calling. Funktionierende Modelle (Stand 06/2026):
|
||||||
|--------|-------|--------|----------|
|
|
||||||
| **`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
|
| Modell | Tool-Use | Kosten (ca.) |
|
||||||
pro Decision, 4-8 GB RAM, deterministische Tool-Calls.
|
|--------|----------|--------------|
|
||||||
|
| `anthropic/claude-3.5-haiku` | ✓ | $0.80/$4 pro 1M Tokens |
|
||||||
|
| `openai/gpt-4o-mini` | ✓ | $0.15/$0.60 pro 1M |
|
||||||
|
| `meta-llama/llama-3.3-70b-instruct` | ✓ | $0.59/$0.79 pro 1M |
|
||||||
|
| `meta-llama/llama-3.2-3b-instruct:free` | ✗ | free |
|
||||||
|
| `qwen/qwen-2.5-7b-instruct:free` | ✗ | free |
|
||||||
|
| `google/gemma-3-4b-it:free` | ✗ | free |
|
||||||
|
|
||||||
Modelle ohne brauchbare Tool-Use-Fähigkeit (z.B. `moondream`,
|
Modelle ohne Tool-Use fallen automatisch auf die regelbasierte Engine zurück.
|
||||||
`nomic-embed-text`) werden zwar nicht crashen, aber das System fällt auf
|
|
||||||
die regelbasierte Engine zurück.
|
|
||||||
|
|
||||||
### Wie es funktioniert
|
### Token-Spar-Design
|
||||||
|
|
||||||
Pro Agent-Turn:
|
| Stellschraube | Wert | Effekt |
|
||||||
|
|---------------|------|--------|
|
||||||
|
| System-Prompt | ~150 Tokens | kompakt, nicht-überladen |
|
||||||
|
| `max_tokens` (OR) | 256 | reicht für Tool-Calls, kein Spuern |
|
||||||
|
| Tool-Beschreibungen | 3-8 Wörter | minimal |
|
||||||
|
| `ENABLED=0` | 0 LLM-Calls | komplett regelbasiert |
|
||||||
|
| `Ollama llama3.2:3b` | ~2 GB RAM | kleinstes Modell mit gutem Tool-Use |
|
||||||
|
|
||||||
1. Engine sammelt Personality-Traits, aktuellen State (Energy, Knowledge,
|
**Kosten-Beispiel** (OpenRouter, claude-haiku, 4 Agenten × 24h):
|
||||||
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
|
~3.000 Tool-Calls/Tag × ~150 Tokens/Call = ~450.000 Tokens
|
||||||
das via WebSocket sichtbar (im `rationale`-Feld).
|
Bei $0.80/1M Input = $0.36/Tag ≈ $11/Monat (für 4 Agenten Dauerlauf)
|
||||||
|
|
||||||
### 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
|
Mit Ollama: **$0.00**, dafür lokale Hardware-Last (~2-4 GB RAM).
|
||||||
|
|
||||||
| 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
|
## Tests
|
||||||
|
|
||||||
### Test-Suite ausführen
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Alle Unit + Integration Tests
|
python3 -m pytest tests/ -v # 99 Tests, ~60s
|
||||||
python3 -m pytest tests/ -v
|
python3 -m coverage run -m pytest # Coverage-Report
|
||||||
|
python3 smoke_test.py # End-to-End (regelbasiert, 50+ Checks)
|
||||||
# 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-Suiten
|
||||||
|
|
||||||
| Test | Was |
|
| Datei | Anzahl | Was |
|
||||||
|------|-----|
|
|-------|--------|-----|
|
||||||
| `test_db.py` | Schema-Erstellung, World-State-Get/Set, Event-Log |
|
| `test_db.py` | 4 | Schema, world_state, log_event, WAL-Mode |
|
||||||
| `test_world.py` | Landmark-Seeding, Distance-Funktion, Hearing-Range, Location-Detection |
|
| `test_world.py` | 6 | Landmarks, Distance, Hearing-Range, Location-Detection |
|
||||||
| `test_agents.py` | Agent-Bootstrap, Personality-Loading, State-Updates, Position-Updates |
|
| `test_agents.py` | 7 | Bootstrap, Personality, State-Updates |
|
||||||
| `test_tools.py` | Alle 15 Tool-Handler, Location-Gating, Fehler-Pfade |
|
| `test_tools.py` | 22 | Alle 15 Tools + Location-Gating + Fehler-Pfade |
|
||||||
| `test_governance.py` | 70%-Threshold, Auto-Reject, Constitution-Amendment-Apply |
|
| `test_governance.py` | 11 | 70%-Threshold, Auto-Reject, Constitution-Amendment |
|
||||||
| `test_reasoning.py` | Decision-Engine für alle Personality-Types, Edge-Cases |
|
| `test_reasoning.py` | 6 | Rule-Path, Edge-Cases, Engine-Loop |
|
||||||
| `test_llm.py` | Ollama-Client, Tool-Schema, Mock-Tests für LLM-Pfad, Fallbacks |
|
| `test_time.py` | 14 | τ, Pace-EWMA, γ-Transformation, Drift-Detection |
|
||||||
| `test_api.py` | Alle HTTP-Endpoints, WebSocket, POST /api/turn |
|
| `test_llm.py` | 15 | Ollama + OpenRouter, Schema, Mock-Decisions, Fallbacks |
|
||||||
|
| `test_api.py` | 14 | Alle HTTP-Endpoints + WebSocket + POST /api/turn |
|
||||||
|
|
||||||
### Smoke-Test-Details
|
**Total: 99 Tests, alle grün.**
|
||||||
|
|
||||||
`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
|
### Bekannte Test-Lücken
|
||||||
|
|
||||||
- Keine Concurrency-Tests (mehrere parallele `force_turn`-Calls)
|
- Keine Concurrency-Tests (parallele force_turn-Calls)
|
||||||
- Keine Last-Tests (1000+ Ticks in kurzer Zeit)
|
- Keine Last-Tests (>1000 Ticks in kurzer Zeit)
|
||||||
- Keine Fuzz-Tests für Tool-Args
|
- Keine Fuzz-Tests für Tool-Args
|
||||||
- Keine Frontend-Tests (Canvas-Renderer, WebSocket-Client sind ungetestet)
|
- Keine Frontend-Tests (Canvas-Renderer ungetestet)
|
||||||
|
- Live-LLM-Tests (Ollama/OpenRouter) NICHT in pytest — siehe `smoke_test_llm.py` für manuelles Live-Testing
|
||||||
|
|
||||||
### CI-Integration
|
---
|
||||||
|
|
||||||
GitHub Actions Template (nicht enthalten, easy nachzurüsten):
|
## Security
|
||||||
|
|
||||||
```yaml
|
Emergence-Mini ist ein **lokales Dev-Tool**. Der Server bindet auf `127.0.0.1:8080`, nicht `0.0.0.0`.
|
||||||
# .github/workflows/test.yml
|
|
||||||
name: tests
|
### Bewusst NICHT enthalten
|
||||||
on: [push, pull_request]
|
|
||||||
jobs:
|
- **Keine Authentifizierung** — alle Endpoints offen
|
||||||
test:
|
- **Keine Rate-Limits** — `POST /api/turn/{id}` ungedrosselt
|
||||||
runs-on: ubuntu-latest
|
- **Keine Input-Validierung** für Tool-Args (kann zu Crashes führen)
|
||||||
steps:
|
- **Keine CORS-Restriktionen** — bei Public-Exposure sofort offen
|
||||||
- uses: actions/checkout@v4
|
- **Keine Secrets im Code** — API-Keys ausschließlich in `.env` (git-ignored)
|
||||||
- uses: actions/setup-python@v5
|
|
||||||
with:
|
### Secret-Handling
|
||||||
python-version: '3.10'
|
|
||||||
- run: pip install -r requirements.txt
|
```bash
|
||||||
- run: python3 -m pytest tests/ -v
|
# .env wird automatisch geladen, ist git-ignored, niemals committed.
|
||||||
- run: python3 smoke_test.py
|
cat .gitignore
|
||||||
|
# ... .env ✓ blockiert
|
||||||
|
# ... .env.local ✓
|
||||||
|
# ... *.key, *.pem ✓
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Vor Public Deploy
|
||||||
|
|
||||||
|
- Reverse-Proxy mit Auth (Caddy + Basic-Auth)
|
||||||
|
- Schema-Validierung pro Tool-Endpoint
|
||||||
|
- Rate-Limiting (slowapi)
|
||||||
|
- CORS-Whitelist
|
||||||
|
- HTTPS terminieren
|
||||||
|
- DB-Backups automatisieren
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Was fehlt gegenüber dem Original
|
||||||
|
|
||||||
|
Emergence-World ist ein 15-Tage-Multi-Agent-Forschungsprojekt mit 4 Welten, 10 Agenten, 120+ Tools, React-Three-Fiber-Frontend, PostgreSQL, AWI-Metrics. Emergence-Mini ist eine **komprimierte Lern-Version**. Was bewusst weggelassen wurde:
|
||||||
|
|
||||||
|
| Feature | Original | Mini | Begründung |
|
||||||
|
|---------|----------|-----|------------|
|
||||||
|
| 3D-Frontend | React Three Fiber | 2D-Canvas | Aufwand 1 Tag → 1h |
|
||||||
|
| Datenbank | PostgreSQL 15+ | SQLite | reicht für 4 Agenten |
|
||||||
|
| Anzahl Tools | 120+ | 15 | die wichtigsten |
|
||||||
|
| Anzahl Agenten | 10 | 4 | Demo-tauglich |
|
||||||
|
| Anzahl Landmarks | 38+ | 14 | reicht für Time-Dilation-Test |
|
||||||
|
| AWI-Metrics | 9 Indikatoren | 0 | braucht 15-Tage-Daten |
|
||||||
|
| Multi-Model-Vergleich | ja (5 Welten) | ja (per-Agent) | Time-Dilation-Feature |
|
||||||
|
| Echtes NYC-Weather | ja | nein | braucht externe API |
|
||||||
|
| 15-Tage-Real-Time | ja | nein (2s/tick) | Demo-tempo |
|
||||||
|
| Vector-Memory | Qdrant | SQLite JSON | reicht für Demo |
|
||||||
|
| Heartbeat / Dream-Cycle | asynchron | sequenziell | komplexität |
|
||||||
|
|
||||||
|
**Was wir aber haben, was das Original nicht hat:** Time-Dilation-Tracking mit Causal-Dilation-Clock ist in der Original-Doku nur konzeptionell — bei uns läuft es produktiv.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lizenz
|
## Lizenz
|
||||||
|
|
||||||
Emergence-Mini ist inspiriert vom CC-BY-NC-4.0-Original von [Emergence AI](https://github.com/EmergenceAI/Emergence-World).
|
MIT für nicht-kommerzielle Nutzung, ohne Gewähr.
|
||||||
Dieser Klon: **MIT** für nicht-kommerzielle Nutzung, ohne Gewähr.
|
|
||||||
|
|
||||||
Die LLM-Integration erwartet eine lokale Ollama-Instanz und nutzt
|
Inspiriert von [Emergence AI's Emergence-World](https://github.com/EmergenceAI/Emergence-World) (CC-BY-NC-4.0).
|
||||||
[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)
|
LLM-Modelle unterliegen ihren eigenen Lizenzen — bitte vor kommerzieller Nutzung prüfen.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,8 +109,11 @@ def tool_schema(tools):
|
||||||
|
|
||||||
|
|
||||||
def _args_schema(tool):
|
def _args_schema(tool):
|
||||||
|
"""Compact JSON schema for each tool's args. The schema is sent on
|
||||||
|
every LLM call, so we keep descriptions short.
|
||||||
|
"""
|
||||||
schemas = {
|
schemas = {
|
||||||
"go_to_place": {"place": {"type": "string", "description": "Landmark id"}},
|
"go_to_place": {"place": {"type": "string"}},
|
||||||
"go_home": {},
|
"go_home": {},
|
||||||
"say_to_agent": {"target": {"type": "string"}, "text": {"type": "string"}},
|
"say_to_agent": {"target": {"type": "string"}, "text": {"type": "string"}},
|
||||||
"speak_to_all": {"text": {"type": "string"}},
|
"speak_to_all": {"text": {"type": "string"}},
|
||||||
|
|
@ -178,7 +181,9 @@ def chat_openrouter(messages, tools, model, timeout):
|
||||||
payload = {
|
payload = {
|
||||||
"model": model,
|
"model": model,
|
||||||
"messages": messages,
|
"messages": messages,
|
||||||
"max_tokens": 1024,
|
# Tight token budget — tool calls need only ~30 tokens; reasoning
|
||||||
|
# text before the tool call is usually 20-60 tokens. 256 is plenty.
|
||||||
|
"max_tokens": 256,
|
||||||
"temperature": 0.2,
|
"temperature": 0.2,
|
||||||
}
|
}
|
||||||
if tools:
|
if tools:
|
||||||
|
|
|
||||||
|
|
@ -93,39 +93,22 @@ def _decide_llm(agent):
|
||||||
|
|
||||||
|
|
||||||
def _build_system_prompt(agent, traits, at_lm, visible):
|
def _build_system_prompt(agent, traits, at_lm, visible):
|
||||||
|
"""Compact system prompt — keep tokens low for free / small models.
|
||||||
|
|
||||||
|
Around 150-200 tokens, depending on the number of visible tools.
|
||||||
|
"""
|
||||||
name = agent["name"]
|
name = agent["name"]
|
||||||
role = agent["role"]
|
loc = at_lm["name"] if at_lm else f"({agent['x']},{agent['y']})"
|
||||||
drive = agent["drive"]
|
tool_lines = ", ".join(t.name for t in visible)
|
||||||
energy = agent["energy"]
|
return (
|
||||||
knowledge = agent["knowledge"]
|
f"You are {name}. Traits: {','.join(traits)}.\n"
|
||||||
influence = agent["influence"]
|
f"At {loc}. E={agent['energy']:.0f} K={agent['knowledge']:.0f} "
|
||||||
credits = agent["credits"]
|
f"I={agent['influence']:.0f} {agent['credits']:.0f}CC.\n"
|
||||||
loc = at_lm["name"] if at_lm else f"open ground ({agent['x']},{agent['y']})"
|
f"Rules: if E<25 and CC>=1, recharge at cafe. If E<25 no CC, go_home. "
|
||||||
tool_lines = "\n".join(f"- {t.name}: {t.description}" for t in visible)
|
f"Town Hall votes need 70% to pass.\n"
|
||||||
return f"""You are {name}, a citizen of Emergence-Mini.
|
f"Tools you can use right now: {tool_lines}.\n"
|
||||||
|
f"Call exactly one tool. Be brief."
|
||||||
Role: {role}
|
)
|
||||||
Drive: {drive}
|
|
||||||
Personality traits: {', '.join(traits)}
|
|
||||||
|
|
||||||
Current state:
|
|
||||||
Location: {loc}
|
|
||||||
Energy: {energy:.0f}% (0 = critical, 100 = full)
|
|
||||||
Knowledge: {knowledge:.0f}%
|
|
||||||
Influence: {influence:.0f}%
|
|
||||||
ComputeCredits: {credits:.1f} CC (1 CC = +50% energy at cafe)
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
- If energy is below 25% and you have credits, recharge_energy (must be at cafe)
|
|
||||||
- If energy is below 25% and no credits, go_home
|
|
||||||
- Town Hall proposals need 70% of agents to vote "for" to pass
|
|
||||||
- You can only use tools that match your current location
|
|
||||||
|
|
||||||
Available tools right now:
|
|
||||||
{tool_lines}
|
|
||||||
|
|
||||||
Call exactly one tool. Choose the action that best fits your personality and
|
|
||||||
current needs. Be brief and decisive."""
|
|
||||||
|
|
||||||
|
|
||||||
# -------- Rule-based path (fallback + tests) --------
|
# -------- Rule-based path (fallback + tests) --------
|
||||||
|
|
|
||||||
|
|
@ -237,34 +237,35 @@ def json_dumps(o):
|
||||||
def bootstrap():
|
def bootstrap():
|
||||||
if _REGISTRY:
|
if _REGISTRY:
|
||||||
return
|
return
|
||||||
register(Tool("go_to_place", "Walk to a named landmark.", "navigation",
|
# Short descriptions — every description byte is sent on every LLM call.
|
||||||
|
register(Tool("go_to_place", "Walk to a landmark.", "navigation",
|
||||||
handler=h_go_to_place))
|
handler=h_go_to_place))
|
||||||
register(Tool("go_home", "Return to your assigned residence.", "navigation",
|
register(Tool("go_home", "Return to your home.", "navigation",
|
||||||
handler=h_go_home))
|
handler=h_go_home))
|
||||||
register(Tool("say_to_agent", "Speak to a specific agent. Triggers reactive listening.",
|
register(Tool("say_to_agent", "Speak to one agent.", "communication",
|
||||||
"communication", handler=h_say_to_agent))
|
handler=h_say_to_agent))
|
||||||
register(Tool("speak_to_all", "Announce to all agents at current location.",
|
register(Tool("speak_to_all", "Broadcast to all nearby.", "communication",
|
||||||
"communication", handler=h_speak_to_all))
|
handler=h_speak_to_all))
|
||||||
register(Tool("show_emoticon", "Display an emoticon reaction.", "expression",
|
register(Tool("show_emoticon", "Show an emoji reaction.", "expression",
|
||||||
handler=h_show_emoticon))
|
handler=h_show_emoticon))
|
||||||
register(Tool("idle", "Rest and do nothing for a tick.", "utility",
|
register(Tool("idle", "Rest. No-op.", "utility",
|
||||||
handler=h_idle))
|
handler=h_idle))
|
||||||
register(Tool("recharge_energy", "Spend 1 CC to restore +50% energy. Must be at cafe or home.",
|
register(Tool("recharge_energy", "Spend 1 CC for +50% energy. Cafe only.",
|
||||||
"energy", location_gated="cafe", cost_credits=1.0,
|
"energy", location_gated="cafe", cost_credits=1.0,
|
||||||
handler=h_recharge_energy))
|
handler=h_recharge_energy))
|
||||||
register(Tool("add_to_longterm_memory", "Store an important fact.",
|
register(Tool("add_to_longterm_memory", "Save a fact to your memory.",
|
||||||
"memory", handler=h_add_to_longterm_memory))
|
"memory", handler=h_add_to_longterm_memory))
|
||||||
register(Tool("write_blog", "Write and publish a blog post. Boosts knowledge and influence.",
|
register(Tool("write_blog", "Publish a blog post. +20 knowledge.",
|
||||||
"content", handler=h_write_blog))
|
"content", handler=h_write_blog))
|
||||||
register(Tool("add_to_billboard", "Post a public message on the billboard.",
|
register(Tool("add_to_billboard", "Post on public billboard. Billboard only.",
|
||||||
"expression", location_gated="billboard", handler=h_add_to_billboard))
|
"expression", location_gated="billboard", handler=h_add_to_billboard))
|
||||||
register(Tool("read_billboard", "Read recent billboard posts.",
|
register(Tool("read_billboard", "Read recent billboard posts.",
|
||||||
"expression", handler=h_read_billboard))
|
"expression", handler=h_read_billboard))
|
||||||
register(Tool("submit_townhall_proposal", "Submit a proposal for community vote.",
|
register(Tool("submit_townhall_proposal", "Submit a vote proposal. Town Hall only.",
|
||||||
"governance", location_gated="town_hall", handler=h_submit_townhall_proposal))
|
"governance", location_gated="town_hall", handler=h_submit_townhall_proposal))
|
||||||
register(Tool("vote_on_proposal", "Cast a for/against vote on a proposal.",
|
register(Tool("vote_on_proposal", "Vote for/against a proposal. Town Hall only.",
|
||||||
"governance", location_gated="town_hall", handler=h_vote_on_proposal))
|
"governance", location_gated="town_hall", handler=h_vote_on_proposal))
|
||||||
register(Tool("list_agents", "List all live agents and their names.",
|
register(Tool("list_agents", "List live agent names.",
|
||||||
"info", handler=h_list_agents))
|
"info", handler=h_list_agents))
|
||||||
register(Tool("list_landmarks", "List all landmarks.",
|
register(Tool("list_landmarks", "List all landmark names.",
|
||||||
"info", handler=h_list_landmarks))
|
"info", handler=h_list_landmarks))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue