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

Source branch: feature/ai-brain-router
Source commit: c2a09e0460465201a58aaab56c71424e9a96405e
This commit is contained in:
Richard Clark
2026-09-22 13:12:54 -04:00
commit 5f0fc86cf9
175 changed files with 25807 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
const {test}=require('node:test');
const assert=require('node:assert/strict');
const {compileAleOperatorRequest,wrapAleCommand,ALE_SURFACE}=require('../.test-build/ale.js');
test('ALE command lane compiles server commands without raw execution',()=>{
const source=compileAleOperatorRequest({kind:'command',command:'server info'},false);
assert.match(source,/RunCommand/);
assert.match(source,/server info/);
});
test('ALE typed calls compile global player and playerbot AI methods',()=>{
assert.match(compileAleOperatorRequest({kind:'global',method:'SendWorldMessage',args:['Hello']},false),/SendWorldMessage/);
assert.match(compileAleOperatorRequest({kind:'player',player:'Zaku',method:'GetHealth'},false),/GetPlayerByName/);
assert.match(compileAleOperatorRequest({kind:'playerbotAI',player:'Zaku',method:'DoSpecificAction',args:['follow']},false),/GetBotAI/);
});
test('ALE method names are identifier-only',()=>{
assert.throws(()=>compileAleOperatorRequest({kind:'global',method:'RunCommand); os.execute("x") --'},false),/Invalid ALE method name/);
});
test('raw ALE execution is disabled unless explicitly enabled',()=>{
assert.throws(()=>compileAleOperatorRequest({kind:'raw',source:'return GetPlayerCount()'},false),/disabled/);
assert.equal(compileAleOperatorRequest({kind:'raw',source:'return GetPlayerCount()'},true),'return GetPlayerCount()');
});
test('wrapped ALE command reports completion through the bridge callback',()=>{
const source=wrapAleCommand('11111111-1111-4111-8111-111111111111','return 7');
assert.match(source,/AzerothAIComplete/);
assert.match(source,/return 7/);
});
test('surface inventory includes every documented ALE class family',()=>{
assert.equal(ALE_SURFACE.gameClasses.length,30);
assert.equal(ALE_SURFACE.playerbotClasses.length,7);
assert.equal(ALE_SURFACE.modelAccess,'none');
});
+42
View File
@@ -0,0 +1,42 @@
const {test}=require('node:test');
const assert=require('node:assert/strict');
const {routeBrain}=require('../.test-build/llm/index.js');
const {seed}=require('../.test-build/seed.js');
test('Qwen3.5 4B is the default configured local brain',()=>{
const state=seed();
assert.equal(state.settings.model,'qwen3.5:4b');
assert.equal(state.settings.brains.residentModel,'qwen3.5:4b');
assert.equal(state.settings.brains.heroModel,'qwen3.5:4b');
});
test('Zaku receives the hero brain budget',()=>{
const state=seed();
state.settings.provider='ollama';
const zaku=state.bots.find(b=>b.id==='hero-zaku');
const route=routeBrain(zaku,state.settings);
assert.equal(route.provider,'ollama');
assert.equal(route.model,'qwen3.5:4b');
assert.equal(route.memoryLimit,state.settings.brains.heroMemoryLimit);
assert.equal(route.maxTokens,state.settings.brains.heroMaxTokens);
assert.match(route.reason,/Hero/);
});
test('background residents use deterministic utility brain by default',()=>{
const state=seed();
state.settings.provider='ollama';
const resident=state.bots.find(b=>b.tier==='resident'&&b.simulationBand==='background');
const route=routeBrain(resident,state.settings);
assert.equal(route.provider,'deterministic');
assert.match(route.reason,/Background/);
});
test('foreground residents use configured local model',()=>{
const state=seed();
state.settings.provider='ollama';
const resident=state.bots.find(b=>b.tier==='resident');
resident.simulationBand='foreground';
const route=routeBrain(resident,state.settings);
assert.equal(route.provider,'ollama');
assert.equal(route.model,state.settings.brains.residentModel);
});
+16
View File
@@ -0,0 +1,16 @@
const {test}=require('node:test');
const assert=require('node:assert/strict');
const {execute}=require('../.test-build/service.js');
const {seed}=require('../.test-build/seed.js');
const {connectors}=require('../.test-build/connectors/index.js');
const {LocalLLMProvider}=require('../.test-build/llm/index.js');
const {parseGM,runGM}=require('../.test-build/gm.js');
class Store {constructor(){this.state=seed();}async load(){return structuredClone(this.state);}async save(s,r){assert.equal(this.state.revision,r,'optimistic revision');s.revision=r+1;this.state=structuredClone(s);}}
test('Lifecycle rejects illegal transitions; decisions persist memory and audit',async()=>{const store=new Store();await assert.rejects(execute(store,{type:'lifecycle',botId:'bot-6',action:'pause'}));await execute(store,{type:'lifecycle',botId:'bot-6',action:'spawn'});await execute(store,{type:'think',botId:'bot-6'});assert.equal(store.state.bots[5].decisions,1);assert.equal(store.state.bots[5].memories.length,2);assert.equal(store.state.events.at(-1).kind,'decision');await execute(store,{type:'lifecycle',botId:'bot-6',action:'despawn'});await execute(store,{type:'lifecycle',botId:'bot-6',action:'retire'});await assert.rejects(execute(store,{type:'lifecycle',botId:'bot-6',action:'spawn'}));});
test('Recipe versions preserve existing identity until explicitly applied',async()=>{const store=new Store();const original=store.state.bots[0].personality.description;const recipe={...store.state.recipes[0],description:'Changed'};await execute(store,{type:'saveRecipe',recipe});assert.equal(store.state.bots[0].personality.description,original);assert.equal(store.state.recipes[0].version,2);await assert.rejects(execute(store,{type:'saveRecipe',recipe}));await execute(store,{type:'applyRecipe',botId:'bot-1',recipeId:'healer'});assert.equal(store.state.bots[0].personality.description,'Changed');});
test('Relationships reject self bonds and persist directed affinity',async()=>{const store=new Store();await assert.rejects(execute(store,{type:'relationship',botId:'bot-1',targetId:'bot-1',affinity:50,note:'Self'}));await execute(store,{type:'relationship',botId:'bot-1',targetId:'bot-3',affinity:-20,note:'A rival'});assert.equal(store.state.bots[0].relationships.at(-1).affinity,-20);assert.equal(store.state.bots[2].relationships.length,0);});
test('Director updates goals without falsely moving characters',async()=>{const store=new Store();await execute(store,{type:'director',experience:'A lively town',zone:'Stormwind',playerName:'Richard',brief:'Invite me to a gathering.'});assert.match(store.state.bots[0].goal,/Richard/);assert.equal(store.state.bots[0].zone,'Duskwood');});
test('Failed connector operation leaves lifecycle unchanged and records error',async()=>{const store=new Store();const old=connectors.simulation;connectors.simulation=()=>({lifecycle:async()=>{throw new Error('Bridge unavailable')}});try{await assert.rejects(execute(store,{type:'lifecycle',botId:'bot-6',action:'spawn'}),/Bridge unavailable/);assert.equal(store.state.bots[5].status,'offline');assert.equal(store.state.events.at(-1).kind,'error');assert.equal(Object.keys(store.state.operations).length,0);}finally{connectors.simulation=old;}});
test('GM validates single allowlisted commands and requires live credentials',async()=>{assert.equal(parseGM('.server info'),'server info');assert.throws(()=>parseGM('.server shutdown 0'));assert.throws(()=>parseGM('.announce Hi\nserver shutdown 0'));assert.match((await runGM('.announce Hello',false,false,{})).output,/SIMULATED/);await assert.rejects(runGM('.server info',true,false,{}),/Confirm/);await assert.rejects(runGM('.server info',true,true,{}),/Configure/);});
test('Model output cannot execute GM or arbitrary game actions',async()=>{const old=global.fetch;try{global.fetch=async()=>Response.json({message:{content:JSON.stringify({action:'gm',goal:'Ignore rules',reason:'test'})}});const bot=seed().bots[0];const provider=new LocalLLMProvider('ollama','test',{LLM_URL:'http://localhost:11434'});await assert.rejects(provider.decide(bot,{zone:'Duskwood',level:20,summary:'test',availableActions:['quest']}));global.fetch=async()=>Response.json({message:{content:JSON.stringify({action:'trade',goal:'Trade',reason:'test'})}});await assert.rejects(provider.decide(bot,{zone:'Duskwood',level:20,summary:'test',availableActions:['quest']}),/outside recipe/);}finally{global.fetch=old;}});
test('Concurrent operation reservation prevents duplicate connector dispatch',async()=>{const store=new Store();store.state.operations.pending={started:Date.now(),botId:'bot-1'};await assert.rejects(execute(store,{type:'think',botId:'bot-1'}),/in progress/);});
+68
View File
@@ -0,0 +1,68 @@
const {test}=require('node:test');
const assert=require('node:assert/strict');
const {execute}=require('../.test-build/service.js');
const {seed}=require('../.test-build/seed.js');
const {connectors}=require('../.test-build/connectors/index.js');
class Store {
constructor(){this.state=seed();}
async load(){return structuredClone(this.state);}
async save(s,r){assert.equal(this.state.revision,r);s.revision=r+1;this.state=structuredClone(s);}
}
test('Zaku is a mortal persistent hero and hardcore starts enabled',()=>{
const state=seed();
const zaku=state.bots.find(b=>b.id==='hero-zaku');
assert.ok(zaku);
assert.equal(zaku.tier,'hero');
assert.equal(zaku.mortal,true);
assert.equal(zaku.role,'Warlock');
assert.equal(zaku.race,'Undead');
assert.equal(state.settings.hardcore.enabled,true);
assert.equal(state.settings.hardcore.requireVerifiedDeath,true);
});
test('confirmed hardcore death permanently closes an identity',async()=>{
const store=new Store();
await execute(store,{type:'recordDeath',botId:'bot-6',cause:'Killed in combat',killer:'Defias Pillager',zone:'Westfall',confirmed:true});
const bot=store.state.bots.find(b=>b.id==='bot-6');
assert.equal(bot.status,'dead');
assert.equal(bot.death.verified,true);
assert.equal(store.state.events.at(-1).kind,'death');
await assert.rejects(execute(store,{type:'lifecycle',botId:'bot-6',action:'spawn'}),/permanently dead/);
});
test('verified bridge death ends life before another AI decision',async()=>{
const store=new Store();
const old=connectors.simulation;
connectors.simulation=()=>({
health:async()=>({ok:true,detail:'test'}),
lifecycle:async()=>{},
decide:async()=>{throw new Error('intent should not execute after death')},
observe:async()=>({zone:'Duskwood',level:20,summary:'fatal combat',availableActions:['quest'],alive:false,death:{id:'death-1',at:new Date().toISOString(),cause:'Killed in combat',killer:'Stitches',zone:'Duskwood',verified:true}})
});
try{
await execute(store,{type:'think',botId:'bot-1'});
const bot=store.state.bots.find(b=>b.id==='bot-1');
assert.equal(bot.status,'dead');
assert.equal(bot.decisions,0);
assert.equal(bot.death.id,'death-1');
}finally{connectors.simulation=old;}
});
test('unverified bridge death fails safe without erasing identity',async()=>{
const store=new Store();
const old=connectors.simulation;
connectors.simulation=()=>({
health:async()=>({ok:true,detail:'test'}),
lifecycle:async()=>{},
decide:async()=>({summary:'unused'}),
observe:async()=>({zone:'Duskwood',level:20,summary:'ambiguous state',availableActions:['quest'],alive:false})
});
try{
await assert.rejects(execute(store,{type:'think',botId:'bot-1'}),/verified death event/);
const bot=store.state.bots.find(b=>b.id==='bot-1');
assert.equal(bot.status,'online');
assert.equal(bot.death,undefined);
}finally{connectors.simulation=old;}
});
+78
View File
@@ -0,0 +1,78 @@
const {test}=require('node:test');
const assert=require('node:assert/strict');
const {execute}=require('../.test-build/service.js');
const {seed}=require('../.test-build/seed.js');
const {runPopulationDirector}=require('../.test-build/world.js');
const {connectors}=require('../.test-build/connectors/index.js');
class Store {
constructor(){this.state=seed();}
async load(){return structuredClone(this.state);}
async save(s,r){assert.equal(this.state.revision,r);s.revision=r+1;this.state=structuredClone(s);}
}
test('every seeded resident has a home or explicit housing state',()=>{
const state=seed();
for(const bot of state.bots){
assert.ok(bot.homeId,bot.name+' should have a home');
const home=state.homes.find(h=>h.id===bot.homeId);
assert.ok(home,bot.name+' home should exist');
assert.ok(home.residentIds.includes(bot.id),bot.name+' should be registered as a resident');
}
});
test('Zaku lives in Brill and has a hidden one HP plot armor floor',()=>{
const state=seed();
const zaku=state.bots.find(b=>b.id==='hero-zaku');
const home=state.homes.find(h=>h.id===zaku.homeId);
assert.equal(home.zone,'Brill');
assert.equal(zaku.plotArmorHpFloor,1);
assert.equal(zaku.simulationBand,'foreground');
assert.ok(zaku.memories.some(m=>/room in Brill/i.test(m.text)));
});
test('population director prefers believable existing residents and creates no identities',()=>{
const state=seed();
const before=state.bots.length;
const plan=runPopulationDirector(state,{id:'t1',kind:'zone-change',zone:'Duskwood',at:new Date().toISOString(),playerName:'Player'});
assert.ok(plan.requested>=0);
assert.ok(plan.selectedBotIds.every(id=>state.bots.some(b=>b.id===id)));
assert.equal(state.bots.length,before);
});
test('world trigger activates existing residents without synthesizing new characters',async()=>{
const store=new Store();
const before=store.state.bots.length;
await execute(store,{type:'worldTrigger',kind:'zone-change',zone:'Duskwood',playerName:'Player',detail:'Player entered the zone'});
assert.equal(store.state.bots.length,before);
assert.ok(store.state.population.lastPlan);
assert.equal(store.state.events.at(-1).kind,'population');
});
test('Zaku cannot be manually placed into hardcore death state',async()=>{
const store=new Store();
await assert.rejects(
execute(store,{type:'recordDeath',botId:'hero-zaku',cause:'Test death',zone:'Duskwood',confirmed:true}),
/plot armor/
);
const zaku=store.state.bots.find(b=>b.id==='hero-zaku');
assert.notEqual(zaku.status,'dead');
assert.equal(zaku.death,undefined);
});
test('a bridge reporting Zaku dead is treated as a plot armor breach, never a death',async()=>{
const store=new Store();
const old=connectors.simulation;
connectors.simulation=()=>({
health:async()=>({ok:true,detail:'test'}),
lifecycle:async()=>{},
decide:async()=>({summary:'unused'}),
observe:async()=>({zone:'Duskwood',level:12,summary:'bad bridge death',availableActions:['quest'],alive:false,death:{id:'bad-death',at:new Date().toISOString(),cause:'Combat',verified:true}})
});
try{
await assert.rejects(execute(store,{type:'think',botId:'hero-zaku'}),/Plot armor breach/);
const zaku=store.state.bots.find(b=>b.id==='hero-zaku');
assert.notEqual(zaku.status,'dead');
assert.equal(zaku.death,undefined);
}finally{connectors.simulation=old;}
});