Import verified AzerothAI snapshot from GitHub
Core tests / core (push) Successful in 9m57s
Full verification / application (push) Failing after 5m16s
Full verification / local-brain (push) Failing after 6m15s
Realm simulation / simulated-live-world (push) Failing after 5m32s
WoW integration lab / real-worldserver (push) Canceled after 17m23s
Core tests / core (push) Successful in 9m57s
Full verification / application (push) Failing after 5m16s
Full verification / local-brain (push) Failing after 6m15s
Realm simulation / simulated-live-world (push) Failing after 5m32s
WoW integration lab / real-worldserver (push) Canceled after 17m23s
Source branch: feature/ai-brain-router Source commit: c2a09e0460465201a58aaab56c71424e9a96405e
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
# AzerothAI Brain Architecture
|
||||
|
||||
AzerothAI separates **who a character is** from **which model thinks for them**.
|
||||
|
||||
Character identity, memories, relationships, housing, goals, mortality history, and possessions remain in AzerothAI. The model is replaceable compute.
|
||||
|
||||
## Default
|
||||
|
||||
The configured local-model default is:
|
||||
|
||||
```text
|
||||
qwen3.5:4b
|
||||
```
|
||||
|
||||
The seed realm remains on the deterministic provider until a local LLM endpoint is configured, so a fresh development install never fails just because Ollama is absent.
|
||||
|
||||
For the mini-PC deployment, enable Ollama after installation and point:
|
||||
|
||||
```text
|
||||
LLM_URL=http://ollama:11434
|
||||
```
|
||||
|
||||
or the equivalent LAN/container address.
|
||||
|
||||
Then select **Ollama** in Server & Models.
|
||||
|
||||
## Router
|
||||
|
||||
The router has separate profiles:
|
||||
|
||||
### Resident brain
|
||||
|
||||
Default:
|
||||
|
||||
```text
|
||||
model: qwen3.5:4b
|
||||
memory retrieval: 8 memories
|
||||
generation budget: 220 tokens
|
||||
```
|
||||
|
||||
Foreground residents use the configured LLM.
|
||||
|
||||
Background residents default to deterministic utility logic so the server does not spend CPU asking every distant character for a language-model decision.
|
||||
|
||||
### Hero brain
|
||||
|
||||
Zaku currently uses:
|
||||
|
||||
```text
|
||||
model: qwen3.5:4b
|
||||
memory retrieval: 16 memories
|
||||
generation budget: 420 tokens
|
||||
```
|
||||
|
||||
The model can later be changed independently to a larger local model or remote OpenAI-compatible model without changing Zaku's identity.
|
||||
|
||||
## Runtime routing
|
||||
|
||||
```text
|
||||
decision requested
|
||||
|
|
||||
v
|
||||
Is provider deterministic?
|
||||
yes -> utility brain
|
||||
no
|
||||
|
|
||||
v
|
||||
Is character background + ordinary resident?
|
||||
yes -> utility brain by default
|
||||
no
|
||||
|
|
||||
+---- resident -> resident model profile
|
||||
|
|
||||
+---- hero/Zaku -> hero model profile
|
||||
```
|
||||
|
||||
This makes compute scale with story importance rather than population count.
|
||||
|
||||
## Character prompt boundary
|
||||
|
||||
The LLM is told that the character lives in Azeroth and should remain in character.
|
||||
|
||||
The prompt intentionally does not expose:
|
||||
|
||||
- ALE credentials
|
||||
- GM commands
|
||||
- database access
|
||||
- Lua execution
|
||||
- packets
|
||||
- server administration
|
||||
- plot armor
|
||||
- simulation/runtime implementation details
|
||||
|
||||
Zaku therefore does not know that the runtime protects him at 1 HP.
|
||||
|
||||
## Installing the default local model
|
||||
|
||||
On a machine running Ollama:
|
||||
|
||||
```bash
|
||||
ollama pull qwen3.5:4b
|
||||
ollama run qwen3.5:4b
|
||||
```
|
||||
|
||||
Verify Ollama is reachable from AzerothAI before switching the decision provider from deterministic to Ollama.
|
||||
|
||||
## Swapping models
|
||||
|
||||
Changing:
|
||||
|
||||
```text
|
||||
brains.residentModel
|
||||
brains.heroModel
|
||||
```
|
||||
|
||||
changes only inference.
|
||||
|
||||
It does not reset:
|
||||
|
||||
- memories
|
||||
- relationships
|
||||
- housing
|
||||
- inventory/world history
|
||||
- personality recipes
|
||||
- goals
|
||||
- death records
|
||||
|
||||
This allows future model upgrades without "replacing" the character.
|
||||
|
||||
## Benchmarking
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
MODELS=qwen3.5:4b,<another-model> OLLAMA_URL=http://127.0.0.1:11434 pnpm bench:brains
|
||||
```
|
||||
|
||||
The benchmark records:
|
||||
|
||||
- response latency
|
||||
- valid JSON rate
|
||||
- allowed-action compliance
|
||||
- approximate response length
|
||||
- raw in-character rationale for manual review
|
||||
|
||||
The benchmark scenarios focus on AzerothAI-specific situations rather than generic academic benchmarks.
|
||||
|
||||
The eventual evaluation set should include at least:
|
||||
|
||||
- friend permanently dies
|
||||
- near-death experience
|
||||
- dungeon invitation
|
||||
- stranger enters home
|
||||
- low money
|
||||
- dangerous travel
|
||||
- betrayal
|
||||
- gift from a friend
|
||||
- argument
|
||||
- rumor
|
||||
- late-night fatigue
|
||||
- conflicting goals
|
||||
- player behaving strangely
|
||||
- seeing a GM-like supernatural event without knowing its cause
|
||||
|
||||
## Future provider routing
|
||||
|
||||
The router is provider-independent.
|
||||
|
||||
Possible later policy:
|
||||
|
||||
```text
|
||||
background residents -> deterministic utility brain
|
||||
foreground residents -> Qwen3.5 4B
|
||||
major NPCs -> larger local model
|
||||
Zaku routine decisions -> local model
|
||||
Zaku rare deep reflection -> optional stronger local/cloud endpoint
|
||||
```
|
||||
|
||||
Cloud providers are optional. Character identities never belong to the provider.
|
||||
@@ -0,0 +1,227 @@
|
||||
# ALE Full-Control Bridge
|
||||
|
||||
AzerothAI uses **ALE (AzerothCore Lua Engine / mod-ale)** as its privileged in-world control plane.
|
||||
|
||||
Official documentation: https://www.azerothcore.org/eluna/index.html
|
||||
|
||||
ALE is an AzerothCore-specific fork and is not guaranteed to be compatible with scripts written for the original Eluna engine.
|
||||
|
||||
## Architecture
|
||||
|
||||
```text
|
||||
┌─────────────────────────┐
|
||||
│ AzerothAI │
|
||||
│ identity / world model │
|
||||
└───────────┬─────────────┘
|
||||
│
|
||||
intents │ operator control
|
||||
│
|
||||
┌───────────────────┴───────────────────┐
|
||||
│ │
|
||||
SAFE GAME CONNECTOR ALE CONTROL PLANE
|
||||
normal AI decisions privileged operator lane
|
||||
│ │
|
||||
│ authenticated queue
|
||||
│ │
|
||||
└───────────────────┬───────────────────┘
|
||||
│
|
||||
┌─────────▼─────────┐
|
||||
│ AzerothCore + ALE │
|
||||
│ worldserver │
|
||||
└───────────────────┘
|
||||
```
|
||||
|
||||
A resident model never receives ALE credentials and cannot submit ALE commands.
|
||||
|
||||
## Why ALE
|
||||
|
||||
The current ALE documentation exposes 30 game-side classes and seven Playerbots classes. It includes large surfaces such as Global, Player, Unit, Creature, GameObject, Map, WorldPacket and PlayerBotAI.
|
||||
|
||||
Examples relevant to AzerothAI include:
|
||||
|
||||
- global timed events and event registration
|
||||
- world/server/player/map/weather/auction hooks
|
||||
- server command execution
|
||||
- world/character/auth database access
|
||||
- spawning creatures and GameObjects
|
||||
- player inventory, money, quests, reputation, skills, spells and teleportation
|
||||
- Unit health, movement, combat, auras, factions and emotes
|
||||
- chat and packet access
|
||||
- Playerbot strategy/action control
|
||||
- Playerbot inventory/quest/world-object observation
|
||||
|
||||
The full operator lane exists so AzerothAI does not need a new REST endpoint every time we want to use another documented ALE method.
|
||||
|
||||
## Two-way transport
|
||||
|
||||
ALE has non-blocking HTTP requests, so the bridge is pull/push:
|
||||
|
||||
### ALE -> AzerothAI
|
||||
|
||||
`ale/azerothai_bridge.lua` sends authoritative world events to:
|
||||
|
||||
`POST /api/bridge/ale/event`
|
||||
|
||||
Initial subscriptions include:
|
||||
|
||||
- server startup/shutdown
|
||||
- weather
|
||||
- game-event start/stop
|
||||
- player login/logout
|
||||
- killed by creature
|
||||
- level changes
|
||||
- chat/whisper
|
||||
- zone/map changes
|
||||
- first login
|
||||
- combat enter/leave
|
||||
- repop/resurrect
|
||||
- achievement
|
||||
- quest acceptance
|
||||
|
||||
A player-zone event automatically feeds the World Population Director.
|
||||
|
||||
Additional ALE event hooks can be added locally or dynamically through the operator lane.
|
||||
|
||||
### AzerothAI -> ALE
|
||||
|
||||
The ALE script polls:
|
||||
|
||||
`GET /api/bridge/ale/poll`
|
||||
|
||||
The server returns one authenticated Lua command chunk. The command executes inside ALE and reports completion to:
|
||||
|
||||
`POST /api/bridge/ale/result`
|
||||
|
||||
Commands and recent event telemetry are stored separately from the main realm-state JSON so frequent bridge polling does not fight with normal realm-state revisions.
|
||||
|
||||
## Operator API
|
||||
|
||||
`POST /api/ale/operator`
|
||||
|
||||
Requires:
|
||||
|
||||
`Authorization: Bearer <ALE_OPERATOR_TOKEN>`
|
||||
|
||||
Supported request modes:
|
||||
|
||||
### AzerothCore command
|
||||
|
||||
```json
|
||||
{"kind":"command","command":"server info"}
|
||||
```
|
||||
|
||||
Compiles to ALE `RunCommand`.
|
||||
|
||||
### Global ALE method
|
||||
|
||||
```json
|
||||
{"kind":"global","method":"SendWorldMessage","args":["The world is changing."]}
|
||||
```
|
||||
|
||||
### Player method
|
||||
|
||||
```json
|
||||
{"kind":"player","player":"Zaku","method":"GetHealth"}
|
||||
```
|
||||
|
||||
Player inherits WorldObject and Unit methods, so this lane also covers inherited methods available to a Player.
|
||||
|
||||
### PlayerBotAI method
|
||||
|
||||
```json
|
||||
{"kind":"playerbotAI","player":"Zaku","method":"DoSpecificAction","args":["follow"]}
|
||||
```
|
||||
|
||||
### Raw ALE Lua
|
||||
|
||||
```json
|
||||
{"kind":"raw","source":"return GetPlayerCount()"}
|
||||
```
|
||||
|
||||
Raw execution is the escape hatch for the complete documented ALE surface: Creature, GameObject, Map, Group, Guild, Item, WorldPacket, specialized Playerbots managers, new ALE methods added later, custom event registration, and multi-step operations.
|
||||
|
||||
It is disabled unless:
|
||||
|
||||
`ALE_RAW_EXEC_ENABLED=true`
|
||||
|
||||
Raw mode is intended only for the private operator environment.
|
||||
|
||||
## Security boundary
|
||||
|
||||
There are two separate credentials:
|
||||
|
||||
- `ALE_BRIDGE_TOKEN`: known only by AzerothAI and the worldserver Lua bridge.
|
||||
- `ALE_OPERATOR_TOKEN`: protects the privileged operator API.
|
||||
|
||||
The LLM/provider code knows neither token and has no route that accepts an ALE command.
|
||||
|
||||
Raw Lua is intentionally not exposed through the ordinary `/api/actions` endpoint.
|
||||
|
||||
## Installation
|
||||
|
||||
Build ALE in AzerothCore:
|
||||
|
||||
```bash
|
||||
cd /path/to/azerothcore/modules
|
||||
git clone https://github.com/azerothcore/mod-ale.git mod-ale
|
||||
```
|
||||
|
||||
Re-run CMake and rebuild AzerothCore.
|
||||
|
||||
Copy:
|
||||
|
||||
`ale/azerothai_bridge.lua`
|
||||
|
||||
into the server's `lua_scripts` directory.
|
||||
|
||||
Add to the private worldserver configuration:
|
||||
|
||||
```ini
|
||||
AzerothAI.Url = "http://127.0.0.1:3000"
|
||||
AzerothAI.Token = "same-value-as-ALE_BRIDGE_TOKEN"
|
||||
AzerothAI.PollMs = "750"
|
||||
AzerothAI.ProtectedCharacter = "Zaku"
|
||||
```
|
||||
|
||||
On AzerothAI configure:
|
||||
|
||||
```text
|
||||
ALE_BRIDGE_TOKEN=<strong random secret>
|
||||
ALE_OPERATOR_TOKEN=<different strong random secret>
|
||||
ALE_RAW_EXEC_ENABLED=true
|
||||
```
|
||||
|
||||
Use raw execution only when AzerothAI is deployed privately and the operator endpoint is not exposed without authentication.
|
||||
|
||||
## Zaku plot armor
|
||||
|
||||
The ALE bridge installs damage modifiers for common player- and creature-originated damage paths.
|
||||
|
||||
When the target name matches `AzerothAI.ProtectedCharacter`:
|
||||
|
||||
```text
|
||||
damage >= current health
|
||||
↓
|
||||
new damage = current health - 1
|
||||
↓
|
||||
Zaku remains at 1 HP
|
||||
```
|
||||
|
||||
This rule lives only in runtime infrastructure.
|
||||
|
||||
Zaku's identity context, memories, and language-model prompt do not include the plot-armor setting.
|
||||
|
||||
AzerothAI still treats any bridge report claiming Zaku died as a control-plane fault rather than writing a death record.
|
||||
|
||||
## What "full control" means
|
||||
|
||||
The bridge provides an operator path to **everything exposed to Lua by the installed ALE build**.
|
||||
|
||||
It does not magically expose private/internal C++ APIs that ALE itself does not bind. If we later need a core function that is not present in ALE, that specific function belongs in a small custom AzerothCore C++ module and can be attached to the same control plane.
|
||||
|
||||
This keeps our architecture layered:
|
||||
|
||||
1. ALE first for documented live-world control.
|
||||
2. AzerothCore commands where appropriate.
|
||||
3. SQL only where a supported API is insufficient.
|
||||
4. Custom C++ bindings only for genuinely unexposed core behavior.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Connector and API contracts
|
||||
|
||||
## Control-plane API
|
||||
|
||||
All write actions go to `POST /api/actions` as JSON. Input validation is in `core/validation.ts`.
|
||||
|
||||
| Action type | Fields | Behavior |
|
||||
|---|---|---|
|
||||
| createBot | name, role, race, recipeId, goal | Creates an offline identity |
|
||||
| lifecycle | botId, action | spawn / pause / resume / despawn / retire |
|
||||
| think | botId | One bounded decision for an online bot |
|
||||
| saveRecipe | recipe | New recipe or optimistic versioned edit |
|
||||
| applyRecipe | botId, recipeId | Applies the latest recipe snapshot |
|
||||
| memory | botId, text, importance | Adds an operator-authored memory |
|
||||
| relationship | botId, targetId, affinity, note | Upserts a directed bond |
|
||||
| director | experience, playerName, zone, brief | Sets non-retired bots' goals |
|
||||
| settings | connector, provider, model | Changes saved runtime selection |
|
||||
| health | none | Tests the currently saved connector |
|
||||
| gm | command, live, confirmed | Human-only GM channel |
|
||||
|
||||
`GET /api/state` returns the snapshot. `GET /api/events` accepts `Last-Event-ID` or `?after=<sequence>` and emits `realm` events. The server closes each batch and asks EventSource to reconnect after 3 seconds. A `gap` event tells clients the cursor predates retention. `GET /api/health` reports database availability and credential configuration booleans only.
|
||||
|
||||
## AzerothCore bot bridge (game-side implementation required)
|
||||
|
||||
Set `BRIDGE_URL` to your bridge root and `BRIDGE_TOKEN` to its bearer token. The adapter sends `Authorization: Bearer ...`, bounded requests, and an opaque `requestId`. The bridge must durably deduplicate request IDs. Do not blindly re-execute a request after a timeout.
|
||||
|
||||
| Endpoint | Request | Successful response |
|
||||
|---|---|---|
|
||||
| GET /v1/health | — | `{ "ok": true, "detail": "..." }` |
|
||||
| GET /v1/bots/:id/observation | — | `{ "zone":"Duskwood", "level":20, "availableActions":["quest","rest"], "summary":"..." }` |
|
||||
| POST /v1/bots/:id/lifecycle | `{ "action":"spawn", "identity": {"id":"...","name":"...","race":"Human","role":"Priest"}, "requestId":"..." }` | `{ "accepted":true }` |
|
||||
| POST /v1/bots/:id/intent | `{ "decision": {"action":"quest","reason":"...","goal":"..."}, "requestId":"..." }` | `{ "accepted":true, "summary":"Intent handed to the bot controller", "zone":"Duskwood" }` |
|
||||
|
||||
The bridge maps stable AzerothAI IDs to actual character GUIDs, validates race/class/faction/version constraints, controls the chosen Playerbots integration, and translates high-level intents to supported game behavior. An `accepted` lifecycle response must mean the requested state is established, not merely queued. Intents may be accepted for execution; their response summaries must not claim completed quests or other outcomes that have not occurred. Reject unsupported operations with non-2xx responses.
|
||||
|
||||
The bridge, not the language model, decides whether a requested action is mechanically possible. The prototype does not write character/world tables directly or send a made-up generic Playerbots command.
|
||||
|
||||
## Adding another game
|
||||
|
||||
Implement `GameConnector` in `core/types.ts`, register a factory in `core/connectors/index.ts`, and add its ID to validated settings/UI choices. Domain memory, relationships, recipe snapshots, and the LLM context remain unchanged. Extend the high-level action vocabulary only when both validation and the connector support it.
|
||||
|
||||
## Models
|
||||
|
||||
Ollama uses `POST <LLM_URL>/api/chat`, `stream:false`, `format:"json"`. Compatible servers use `POST <LLM_URL>/v1/chat/completions` and JSON-object response format. Set `LLM_URL` to the root without `/v1`; optionally set `LLM_API_KEY` for authenticated gateways. Requests have a 25-second timeout and an output limit. Decisions are schema-validated and intersected with both recipe activities and observed available actions. Invalid output fails visibly without fallback to fabricated success.
|
||||
|
||||
The context includes identity, recipe, current goal, eight important memories, ten relationships, and the latest observation. Memories/observations are marked untrusted. Memory retrieval is intentionally simple, not vector search. The deterministic provider is an explicitly labeled simulator, not an LLM.
|
||||
|
||||
## GM SOAP
|
||||
|
||||
Configure `SOAP_URL`, `SOAP_USER`, and `SOAP_PASSWORD`. `core/gm.ts` posts a SOAP `executeCommand` envelope in namespace `urn:AC`, with Basic authentication. Leading dots are removed for console use; XML metacharacters are escaped. Multiple commands, control characters, and commands outside the allowlist are rejected.
|
||||
|
||||
Supported: `server info`, `announce <text>`, `teleport name <character> <location>`, `pinfo <character>`, `server motd`. Authorization and command availability still depend on the actual AzerothCore branch and account permissions. SOAP results and faults are reported; nothing calls the GM client from an LLM provider.
|
||||
|
||||
Position/selection-dependent commands such as `summon`, NPC spawning at the GM location, visibility, and flying require an in-game session or a purpose-built game-side adapter. They are not misleadingly offered as working remote buttons.
|
||||
|
||||
Official references used for the protocol:
|
||||
- https://www.azerothcore.org/wiki/remote-access
|
||||
- https://www.azerothcore.org/wiki/gm-commands
|
||||
- https://docs.ollama.com/api/chat
|
||||
@@ -0,0 +1,158 @@
|
||||
# Living World, Housing, Population Direction, and Zaku Plot Armor
|
||||
|
||||
## Principle
|
||||
|
||||
Residents should experience Azeroth as their world, not as a simulation session.
|
||||
|
||||
AzerothAI therefore separates two layers:
|
||||
|
||||
- **Diegetic character context:** home, possessions, relationships, routines, goals, memories, danger, travel, work, social life.
|
||||
- **Operator/runtime context:** simulation bands, capacity budgets, connector state, plot armor, scheduling, infrastructure.
|
||||
|
||||
Runtime-only facts must not be included in prompts or memories given to residents.
|
||||
|
||||
## Housing
|
||||
|
||||
Every seeded resident has a persistent home record.
|
||||
|
||||
A home includes:
|
||||
|
||||
- type: house, inn, barracks, guild housing, camp, or homeless
|
||||
- zone
|
||||
- capacity
|
||||
- residents
|
||||
- owners
|
||||
- storage capacity
|
||||
- safety rating
|
||||
- description
|
||||
|
||||
A resident stores a `homeId` and routine. Moving home produces a normal in-world memory such as "I moved to..." rather than an infrastructure message.
|
||||
|
||||
Zaku begins with a rented room in Brill.
|
||||
|
||||
## World Population Director
|
||||
|
||||
The population director implements the whiteboard flow:
|
||||
|
||||
```
|
||||
EVENT TRIGGER
|
||||
zone change / interaction / time / manual
|
||||
|
|
||||
v
|
||||
CAPACITY CHECK
|
||||
zone max
|
||||
server max
|
||||
foreground AI budget
|
||||
background AI budget
|
||||
|
|
||||
v
|
||||
VALIDITY / BELIEVABILITY
|
||||
already in zone?
|
||||
home in zone?
|
||||
preferred zone?
|
||||
personality fit?
|
||||
alive / active identity?
|
||||
|
|
||||
v
|
||||
ACTIVATE OR ROUTE EXISTING RESIDENTS
|
||||
```
|
||||
|
||||
The director does **not** create disposable people to fill a zone.
|
||||
|
||||
If a zone wants six active residents but only three believable existing residents are available, it activates three and records the shortfall. New identities must be created through explicit population growth systems later.
|
||||
|
||||
## Simulation bands
|
||||
|
||||
Residents can exist at three simulation detail levels:
|
||||
|
||||
- **foreground** — near the human player or in an important active scene; detailed decisions and conversations.
|
||||
- **background** — alive elsewhere in the world; lower-frequency decisions.
|
||||
- **dormant** — sleeping, inactive, or safely abstracted; life state persists without constant model inference.
|
||||
|
||||
This lets a large persistent population exist on modest hardware without running an LLM for every resident every second.
|
||||
|
||||
## Zaku plot armor
|
||||
|
||||
Zaku is the one explicit exception to the normal Hardcore mortality mechanic.
|
||||
|
||||
His runtime identity contains:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "hero-zaku",
|
||||
"plotArmorHpFloor": 1
|
||||
}
|
||||
```
|
||||
|
||||
This field is **runtime-only**. Do not place it in Zaku's LLM prompt, memory, dialogue context, biography, or observable world state.
|
||||
|
||||
Zaku should believe the same thing other residents believe: death is possible and danger matters.
|
||||
|
||||
### Required AzerothCore behavior
|
||||
|
||||
The live worldserver/bridge must enforce the floor at the combat mechanics layer. AzerothAI cannot reliably prevent lethal damage after the fact.
|
||||
|
||||
Conceptually:
|
||||
|
||||
```text
|
||||
if character.plotArmorHpFloor > 0:
|
||||
resolvedHp = max(character.plotArmorHpFloor, resolvedHp)
|
||||
suppressDeathTransition()
|
||||
```
|
||||
|
||||
For Zaku, any damage event that would normally produce 0 or negative HP must leave him at exactly 1 HP.
|
||||
|
||||
The character can still:
|
||||
|
||||
- lose a fight
|
||||
- flee
|
||||
- be crowd-controlled
|
||||
- run out of mana
|
||||
- suffer durability loss if normal mechanics produce it
|
||||
- remember near-death experiences
|
||||
- become more risk-averse
|
||||
|
||||
He simply cannot enter the dead state.
|
||||
|
||||
### Defense in depth
|
||||
|
||||
AzerothAI also blocks death at the control-plane layer.
|
||||
|
||||
If an operator attempts to record Zaku as permanently dead, the action is rejected.
|
||||
|
||||
If the AzerothCore bridge reports Zaku as dead, AzerothAI treats it as a **plot armor breach**, records an error, preserves the identity, and refuses to write a death record.
|
||||
|
||||
This protects Zaku from a bridge bug, but the live worldserver still needs the HP clamp so players never visually see him die.
|
||||
|
||||
## AzerothCore lifecycle payload
|
||||
|
||||
The bridge receives the runtime rule when a resident is spawned or managed:
|
||||
|
||||
```json
|
||||
{
|
||||
"identity": {
|
||||
"id": "hero-zaku",
|
||||
"name": "Zaku",
|
||||
"race": "Undead",
|
||||
"role": "Warlock",
|
||||
"tier": "hero",
|
||||
"mortal": true,
|
||||
"plotArmorHpFloor": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Normal residents use `plotArmorHpFloor: 0`.
|
||||
|
||||
## Future work
|
||||
|
||||
Next useful steps are:
|
||||
|
||||
1. authoritative player-zone events from AzerothCore into `worldTrigger`
|
||||
2. interaction/hearing-radius triggers
|
||||
3. world-time scheduler that wakes residents and routes them home
|
||||
4. home storage and possessions
|
||||
5. travel-time-aware routing rather than immediate simulation relocation
|
||||
6. jobs, rent, households, inheritance, and estates
|
||||
7. capacity telemetry based on the actual mini-PC load
|
||||
8. near-death memories and risk psychology, especially for Zaku
|
||||
@@ -0,0 +1,39 @@
|
||||
# Running this prototype
|
||||
|
||||
## Runtime and persistence
|
||||
|
||||
The frontend is React/TypeScript, served by Vinext in a Cloudflare-compatible Worker. The database is D1 in hosting and local SQLite under `.wrangler/state` in the emulator. `db/schema.ts` and the checked-in Drizzle migration own schema changes; startup seeds only an empty realm row.
|
||||
|
||||
The current store is a single versioned realm document: good for a small private prototype, not a high-volume production world. Limits: 100 identities, 100 recipes, 100 recent memories per bot, and 500 recent events. It uses optimistic compare-and-swap and one 60-second realm-operation lease to avoid overlapping outbound calls. An expired lease is audited before new work. The full HTTP operation can take up to 49 seconds (observation + model + intent). It is not an exactly-once distributed system: a remote success followed by a crash or database failure needs operator reconciliation. A production bridge must persist idempotency keys and add an operation-status endpoint and reconciliation worker.
|
||||
|
||||
Retirement is a terminal state in this prototype and preserves historical data. Pause means no new high-level decisions; the bridge must implement and acknowledge the appropriate bot pause semantics. Switching connectors requires all online/paused identities to be despawned so simulation state does not masquerade as live state.
|
||||
|
||||
## Private access
|
||||
|
||||
The hosted Site is owner-private. The application is a single-realm admin prototype and relies on that access gate; it is not ready for public sharing or multiple roles. All users admitted to the Site would be realm administrators. Write routes reject a mismatching Origin header; this is not authentication. Local preview binds to loopback and has no separate app login. Do not expose it on a public interface without an authenticated reverse proxy and explicit operator authorization.
|
||||
|
||||
Live bridge and model URLs are configured server-side only and must point to trusted services. The UI never receives credentials. Use a trusted private network or authenticated HTTPS gateway for hosted-to-home access; do not expose raw SOAP or an unauthenticated Ollama endpoint publicly.
|
||||
|
||||
## AzerothCore / game-side setup
|
||||
|
||||
A real core/Playerbots build and version have not been supplied. This code therefore implements the control plane, the HTTP bridge client contract, and the direct GM SOAP transport, but does not claim to have deployed a worldserver or a Playerbots module. Bot lifecycle and observation endpoints require a game-side adapter specific to the chosen installation.
|
||||
|
||||
For GM SOAP, enable SOAP in your worldserver configuration and use an account whose permissions allow the desired remote commands; consult the official remote-access documentation. Verify connectivity privately before enabling the live toggle. The app requires confirmation for every live GM request and retains command/result audit records inside the bounded event history. A timeout can mean an unknown remote result; inspect the worldserver before resubmitting.
|
||||
|
||||
## Model setup
|
||||
|
||||
A local Ollama service and an installed model are optional. Point `LLM_URL` at its root URL and choose Ollama in Server & Models, then save. The default model name is only a suggested configuration string; this app does not pull or install model weights. No provider claims success until its response parses and its selected action is allowed.
|
||||
|
||||
Use the deterministic provider to exercise the UI and lifecycle without any model. It prioritizes recipe traits and adds identity/decision variation; it is not evidence of sophisticated autonomous behavior.
|
||||
|
||||
## Current limits / next integration work
|
||||
|
||||
- Decisions run manually from bot profiles. No unattended scheduler or background population loop yet.
|
||||
- Director context is operator-entered; no automatic real-player location tracking yet.
|
||||
- Relationships are operator-authored and asymmetric; no automatic social inference yet.
|
||||
- No simulated combat, pathfinding, quests, loot, or actual WoW client automation.
|
||||
- No map artwork or fake world telemetry. The realm pulse uses known bot locations.
|
||||
- No live AzerothCore or live LLM end-to-end test was possible without those services.
|
||||
- Before a long-running live realm: implement the game-side bridge, normalize storage, add task queues/reconciliation, permanent audit retention, per-role authorization, model budgets, and observation ingestion.
|
||||
|
||||
The project is deliberately runnable now in simulation, with those boundaries visible in the interface.
|
||||
@@ -0,0 +1,84 @@
|
||||
# Zaku + Hardcore World Mode
|
||||
|
||||
AzerothAI now supports a persistent **hero agent** tier and a realm-level Hardcore ruleset. Zaku is the first hero agent.
|
||||
|
||||
## Design rule
|
||||
|
||||
AzerothCore remains the authority for game mechanics. AzerothAI owns identity, memory, relationships, goals, and permanent life history.
|
||||
|
||||
Zaku does not receive GM powers or resurrection privileges. He is special because his cognition and memory are richer, not because the world rules do not apply to him.
|
||||
|
||||
## One life
|
||||
|
||||
When `settings.hardcore.enabled` is true, a mortal character that enters the `dead` state can never spawn, resume, think, or be recycled under that identity.
|
||||
|
||||
The death record preserves:
|
||||
|
||||
- character identity
|
||||
- level
|
||||
- zone
|
||||
- timestamp
|
||||
- cause
|
||||
- killer when known
|
||||
- source of the death event
|
||||
- whether the event was verified
|
||||
|
||||
The existing identity, memories, relationships, and history stay in the realm so surviving characters can remember the dead.
|
||||
|
||||
## Fail-safe death verification
|
||||
|
||||
A temporary disconnect, loading problem, ghost state, or bad bridge response must not erase a months-old character.
|
||||
|
||||
With `requireVerifiedDeath: true`, the AzerothCore bridge must return a verified death event before AzerothAI permanently closes the identity.
|
||||
|
||||
Example observation:
|
||||
|
||||
```json
|
||||
{
|
||||
"zone": "Duskwood",
|
||||
"level": 27,
|
||||
"summary": "Zaku was killed during combat.",
|
||||
"availableActions": [],
|
||||
"alive": false,
|
||||
"death": {
|
||||
"id": "worldserver-death-event-93822",
|
||||
"at": "2026-09-20T18:00:00Z",
|
||||
"cause": "Killed in combat",
|
||||
"killer": "Stitches",
|
||||
"zone": "Duskwood",
|
||||
"verified": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If `alive` is false but the verified event is missing, AzerothAI fails safe: the bot is not deleted and no new AI decision is sent.
|
||||
|
||||
## Zaku
|
||||
|
||||
Seed identity:
|
||||
|
||||
- ID: `hero-zaku`
|
||||
- Race: Undead
|
||||
- Class: Warlock
|
||||
- Tier: hero
|
||||
- Mortal: yes
|
||||
- Starting zone: Deathknell
|
||||
- Starting level: 1
|
||||
|
||||
His starting goal is to survive, build a life, form relationships, and pursue goals even while the human player is offline.
|
||||
|
||||
His long-term memory uses the same durable memory and relationship system as every resident. Hero status is intended to unlock richer planning later, not rule-breaking.
|
||||
|
||||
## Memorialization
|
||||
|
||||
When a character permanently dies, surviving agents who had a relationship with that character receive a high-importance memory of the death. Hero agents also remember realm deaths so important losses can influence future behavior.
|
||||
|
||||
## Simulation testing
|
||||
|
||||
The control plane supports an explicit confirmed `recordDeath` action for simulation and administrative testing. This action requires `confirmed: true`.
|
||||
|
||||
Live AzerothCore deaths should normally originate from the bridge's verified game-server event rather than manual death recording.
|
||||
|
||||
## Next live-server step
|
||||
|
||||
The AzerothCore bridge should subscribe to or expose authoritative player death state and produce stable unique death event IDs. The bridge should only set `verified: true` after the worldserver has committed the death event for that character.
|
||||
Reference in New Issue
Block a user