336 lines
9.1 KiB
Markdown
336 lines
9.1 KiB
Markdown
|
|
# Multi-User AI Bridge for MUDs
|
||
|
|
|
||
|
|
A bridge server that enables multiple simultaneous users to interact with an AI agent (Timmy) inside a persistent virtual world built on [Evennia](https://www.evennia.com/). Each user gets an isolated conversation context while sharing the same game environment — rooms, objects, and other players.
|
||
|
|
|
||
|
|
## What It Is
|
||
|
|
|
||
|
|
Traditional AI chatbots operate in isolation: one user, one conversation, no shared world. This project embeds a sovereign AI agent inside a MUD (Multi-User Dungeon), solving three problems at once:
|
||
|
|
|
||
|
|
- **Session isolation** — each user has their own conversation history
|
||
|
|
- **Shared environment** — all users see the same rooms, objects, and each other
|
||
|
|
- **Organic social interaction** — users encounter the AI naturally within a game space
|
||
|
|
|
||
|
|
The bridge runs as an HTTP server alongside Evennia. Evennia commands call the bridge API to get the AI agent's responses.
|
||
|
|
|
||
|
|
## Architecture
|
||
|
|
|
||
|
|
```
|
||
|
|
+-----------+ +-----------+ +-----------+
|
||
|
|
| User A | | User B | | User C |
|
||
|
|
| (telnet) | | (telnet) | | (telnet) |
|
||
|
|
+-----+-----+ +-----+-----+ +-----+-----+
|
||
|
|
| | |
|
||
|
|
v v v
|
||
|
|
+---------------------------------------------------+
|
||
|
|
| Evennia MUD |
|
||
|
|
| Rooms, Objects, Commands, World State (JSON) |
|
||
|
|
+------------------------+--------------------------+
|
||
|
|
|
|
||
|
|
v
|
||
|
|
+---------------------------------------------------+
|
||
|
|
| Multi-User Bridge (HTTP) |
|
||
|
|
| |
|
||
|
|
| SessionManager PresenceManager |
|
||
|
|
| +------------------+ +-----------------------+ |
|
||
|
|
| | Session A | | Room tracking | |
|
||
|
|
| | - user_id | | User enter/leave | |
|
||
|
|
| | - conversation | | Chat events | |
|
||
|
|
| | - AIAgent | +-----------------------+ |
|
||
|
|
| | | |
|
||
|
|
| | Session B | +-----------------------+ |
|
||
|
|
| | - user_id | | Crisis Protocol | |
|
||
|
|
| | - conversation | | - 988 Lifeline | |
|
||
|
|
| | - AIAgent | | - Crisis Text Line | |
|
||
|
|
| | | | - Grounding exercise | |
|
||
|
|
| | Session C | +-----------------------+ |
|
||
|
|
| | - ... | |
|
||
|
|
| +------------------+ |
|
||
|
|
+------------------------+--------------------------+
|
||
|
|
|
|
||
|
|
v
|
||
|
|
+---------------------------------------------------+
|
||
|
|
| Hermes Agent (AIAgent) |
|
||
|
|
| Model: xiaomi/mimo-v2-pro | Provider: nous |
|
||
|
|
| Tools: file, terminal |
|
||
|
|
| Per-session system prompt with world context |
|
||
|
|
+---------------------------------------------------+
|
||
|
|
```
|
||
|
|
|
||
|
|
## API Reference
|
||
|
|
|
||
|
|
### Health & Sessions
|
||
|
|
|
||
|
|
#### `GET /bridge/health`
|
||
|
|
Health check. Returns bridge status and active session count.
|
||
|
|
|
||
|
|
**Response:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "ok",
|
||
|
|
"active_sessions": 3,
|
||
|
|
"timestamp": "2026-04-12T20:30:00"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### `GET /bridge/sessions`
|
||
|
|
List all active user sessions.
|
||
|
|
|
||
|
|
**Response:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"sessions": [
|
||
|
|
{
|
||
|
|
"user": "Alice",
|
||
|
|
"room": "The Threshold",
|
||
|
|
"messages": 12,
|
||
|
|
"last_active": "2026-04-12T20:29:45",
|
||
|
|
"created": "2026-04-12T20:15:00"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Room & Presence
|
||
|
|
|
||
|
|
#### `GET /bridge/world/<room_name>`
|
||
|
|
Get world state data for a specific room.
|
||
|
|
|
||
|
|
**Response:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"room": "The Threshold",
|
||
|
|
"data": {
|
||
|
|
"desc_base": "A quiet room with a green LED on the wall.",
|
||
|
|
"visitor_history": ["Alice", "Bob"]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### `GET /bridge/room/<room_name>/players`
|
||
|
|
List players currently in a room.
|
||
|
|
|
||
|
|
**Response:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"room": "The Threshold",
|
||
|
|
"players": [
|
||
|
|
{"user_id": "alice_01", "username": "Alice"},
|
||
|
|
{"user_id": "bob_02", "username": "Bob"}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### `GET /bridge/room/<room_name>/events[?since=<timestamp>]`
|
||
|
|
Get recent room events (presence + chat). Optionally filter by timestamp.
|
||
|
|
|
||
|
|
**Response:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"room": "The Threshold",
|
||
|
|
"events": [
|
||
|
|
{
|
||
|
|
"type": "presence",
|
||
|
|
"event": "enter",
|
||
|
|
"user_id": "alice_01",
|
||
|
|
"username": "Alice",
|
||
|
|
"room": "The Threshold",
|
||
|
|
"timestamp": "2026-04-12T20:15:00"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"type": "say",
|
||
|
|
"event": "message",
|
||
|
|
"user_id": "alice_01",
|
||
|
|
"username": "Alice",
|
||
|
|
"room": "The Threshold",
|
||
|
|
"message": "Hello everyone!",
|
||
|
|
"timestamp": "2026-04-12T20:15:30"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Chat & Actions
|
||
|
|
|
||
|
|
#### `POST /bridge/chat`
|
||
|
|
Send a message to Timmy. Creates or retrieves a per-user session with isolated conversation context.
|
||
|
|
|
||
|
|
**Request:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"user_id": "alice_01",
|
||
|
|
"username": "Alice",
|
||
|
|
"message": "What do you see in this room?",
|
||
|
|
"room": "The Threshold"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"response": "I see bare stone walls and a single green LED pulsing softly.",
|
||
|
|
"user": "Alice",
|
||
|
|
"room": "The Threshold",
|
||
|
|
"session_messages": 5
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### `POST /bridge/say`
|
||
|
|
Say something visible to all players in the room (not directed at Timmy).
|
||
|
|
|
||
|
|
**Request:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"user_id": "alice_01",
|
||
|
|
"username": "Alice",
|
||
|
|
"message": "Anyone else here?",
|
||
|
|
"room": "The Threshold"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"ok": true,
|
||
|
|
"event": {
|
||
|
|
"type": "say",
|
||
|
|
"event": "message",
|
||
|
|
"user_id": "alice_01",
|
||
|
|
"username": "Alice",
|
||
|
|
"room": "The Threshold",
|
||
|
|
"message": "Anyone else here?",
|
||
|
|
"timestamp": "2026-04-12T20:20:00"
|
||
|
|
},
|
||
|
|
"recipients": [
|
||
|
|
{"user_id": "bob_02", "username": "Bob"}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### `POST /bridge/move`
|
||
|
|
Move a user to a new room. Triggers leave/enter presence events.
|
||
|
|
|
||
|
|
**Request:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"user_id": "alice_01",
|
||
|
|
"room": "The Garden"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response:**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"ok": true,
|
||
|
|
"room": "The Garden",
|
||
|
|
"events": [
|
||
|
|
{
|
||
|
|
"type": "presence",
|
||
|
|
"event": "leave",
|
||
|
|
"user_id": "alice_01",
|
||
|
|
"username": "Alice",
|
||
|
|
"room": "The Threshold",
|
||
|
|
"timestamp": "2026-04-12T20:22:00"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"type": "presence",
|
||
|
|
"event": "enter",
|
||
|
|
"user_id": "alice_01",
|
||
|
|
"username": "Alice",
|
||
|
|
"room": "The Garden",
|
||
|
|
"timestamp": "2026-04-12T20:22:00"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Quick Start
|
||
|
|
|
||
|
|
### Prerequisites
|
||
|
|
|
||
|
|
- Python 3.10+
|
||
|
|
- Evennia installed and configured
|
||
|
|
- Hermes Agent available at `~/.hermes/hermes-agent`
|
||
|
|
|
||
|
|
### 1. Start the Bridge
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /tmp/mud-bridge
|
||
|
|
python multi_user_bridge.py
|
||
|
|
```
|
||
|
|
|
||
|
|
The bridge starts on `127.0.0.1:4004` by default.
|
||
|
|
|
||
|
|
### 2. Configure Evennia
|
||
|
|
|
||
|
|
The Evennia command handler (`timmy_commands.py`) calls the bridge API. Set the bridge URL in your Evennia config:
|
||
|
|
|
||
|
|
```python
|
||
|
|
TIMMY_BRIDGE_HOST = os.environ.get('TIMMY_BRIDGE_HOST', '127.0.0.1')
|
||
|
|
TIMMY_BRIDGE_PORT = int(os.environ.get('TIMMY_BRIDGE_PORT', 4004))
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Connect
|
||
|
|
|
||
|
|
Telnet to your Evennia server and use the `talk` command to chat with Timmy:
|
||
|
|
|
||
|
|
```
|
||
|
|
> talk Hello, Timmy!
|
||
|
|
Timmy: The green LED pulses. "Hello. Welcome to The Tower."
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Test the API
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Health check
|
||
|
|
curl http://127.0.0.1:4004/bridge/health
|
||
|
|
|
||
|
|
# Chat with Timmy
|
||
|
|
curl -X POST http://127.0.0.1:4004/bridge/chat \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-d '{"user_id":"test","username":"Tester","message":"Hello!","room":"The Threshold"}'
|
||
|
|
|
||
|
|
# Check who's in a room
|
||
|
|
curl http://127.0.0.1:4004/bridge/room/The%20Threshold/players
|
||
|
|
```
|
||
|
|
|
||
|
|
## Crisis Protocol
|
||
|
|
|
||
|
|
Timmy is designed with crisis intervention in mind. If a user expresses crisis signals (suicide, self-harm, hopelessness, desperation), the agent immediately responds with ALL of the following in the very first reply:
|
||
|
|
|
||
|
|
1. **"Are you safe right now?"** — always asked first
|
||
|
|
2. **988 Suicide & Crisis Lifeline** — call or text 988 (US)
|
||
|
|
3. **Crisis Text Line** — text HOME to 741741
|
||
|
|
4. **Grounding exercise** — Name 5 things you see, 4 you can touch, 3 you hear, 2 you smell, 1 you taste
|
||
|
|
|
||
|
|
The crisis protocol is embedded in the system prompt for every session. The agent never computes the value of a human life. It is present. It is in the room.
|
||
|
|
|
||
|
|
## Configuration
|
||
|
|
|
||
|
|
| Variable | Default | Description |
|
||
|
|
|---|---|---|
|
||
|
|
| `TIMMY_BRIDGE_PORT` | `4004` | Bridge HTTP server port |
|
||
|
|
| `TIMMY_BRIDGE_HOST` | `127.0.0.1` | Bridge bind address |
|
||
|
|
| `HERMES_PATH` | `~/.hermes/hermes-agent` | Path to Hermes Agent runtime |
|
||
|
|
| `WORLD_DIR` | `~/.timmy/evennia/timmy_world` | Evennia world data directory |
|
||
|
|
|
||
|
|
## Session Management
|
||
|
|
|
||
|
|
- **Max sessions:** 20 concurrent users
|
||
|
|
- **Session timeout:** 3600 seconds (1 hour) of inactivity
|
||
|
|
- **Eviction policy:** Least recently active session is evicted when at capacity
|
||
|
|
- **Room events:** Last 50 events per room are retained
|
||
|
|
|
||
|
|
## Paper
|
||
|
|
|
||
|
|
This project accompanies the paper:
|
||
|
|
|
||
|
|
> **"Sovereign in the Room: Multi-User AI Interaction in Persistent Virtual Worlds"**
|
||
|
|
>
|
||
|
|
> We present an architecture for deploying sovereign AI agents as persistent, multi-user NPCs in text-based virtual worlds (MUDs), enabling isolated crisis-aware conversations within a shared environment, and demonstrate its application to suicide prevention through the Tower — a virtual safe space.
|
||
|
|
|
||
|
|
See `paper/autoreason-mud-paper.md` for the full draft.
|
||
|
|
|
||
|
|
## License
|
||
|
|
|
||
|
|
This is a research project. See the paper directory for experiment data and methodology.
|