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,126 @@
|
||||
export type ConversationChannel='say'|'whisper';
|
||||
|
||||
export type ConversationRequest={
|
||||
id:string;
|
||||
createdAt:string;
|
||||
speakerName:string;
|
||||
message:string;
|
||||
channel:ConversationChannel;
|
||||
zoneName:string;
|
||||
receiver:string;
|
||||
selectedPlayer:string;
|
||||
nearbyBots:string[];
|
||||
status:'pending'|'processing'|'completed'|'failed';
|
||||
attempts:number;
|
||||
};
|
||||
|
||||
async function ensure(db:D1Database){
|
||||
await db.prepare(`CREATE TABLE IF NOT EXISTS conversation_requests (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
speaker_name TEXT NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
channel TEXT NOT NULL,
|
||||
zone_name TEXT NOT NULL,
|
||||
receiver TEXT NOT NULL,
|
||||
selected_player TEXT NOT NULL,
|
||||
nearby_bots TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
attempts INTEGER NOT NULL DEFAULT 0,
|
||||
started_at TEXT,
|
||||
completed_at TEXT,
|
||||
result TEXT,
|
||||
error TEXT
|
||||
)`).run();
|
||||
await db.prepare(`CREATE INDEX IF NOT EXISTS idx_conversation_requests_status_created
|
||||
ON conversation_requests(status,created_at)`).run();
|
||||
}
|
||||
|
||||
function text(payload:Record<string,unknown>,key:string,max:number){
|
||||
const value=payload[key];
|
||||
return typeof value==='string'?value.trim().slice(0,max):'';
|
||||
}
|
||||
|
||||
export async function queueConversationEvent(db:D1Database,kind:string,payload:Record<string,unknown>){
|
||||
if(payload.isBot===true)return null;
|
||||
if(kind!=='player.chat'&&kind!=='player.whisper')return null;
|
||||
|
||||
const speakerName=text(payload,'name',40);
|
||||
const message=text(payload,'message',500);
|
||||
if(!speakerName||!message)return null;
|
||||
if(message.startsWith('.')||message.startsWith('!'))return null;
|
||||
|
||||
if(kind==='player.whisper'&&payload.receiverIsBot!==true)return null;
|
||||
if(kind==='player.chat'&&!text(payload,'selectedPlayer',40)&&!text(payload,'nearbyBots',1000))return null;
|
||||
|
||||
await ensure(db);
|
||||
const id=crypto.randomUUID();
|
||||
const createdAt=new Date().toISOString();
|
||||
const channel:ConversationChannel=kind==='player.whisper'?'whisper':'say';
|
||||
await db.prepare(`INSERT INTO conversation_requests
|
||||
(id,created_at,speaker_name,message,channel,zone_name,receiver,selected_player,nearby_bots,status,attempts)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,'pending',0)`)
|
||||
.bind(
|
||||
id,createdAt,speakerName,message,channel,
|
||||
text(payload,'zoneName',120),
|
||||
text(payload,'receiver',40),
|
||||
text(payload,'selectedPlayer',40),
|
||||
text(payload,'nearbyBots',1000)
|
||||
).run();
|
||||
return {id,createdAt};
|
||||
}
|
||||
|
||||
export async function leaseConversation(db:D1Database):Promise<ConversationRequest|null>{
|
||||
await ensure(db);
|
||||
const staleBefore=new Date(Date.now()-90_000).toISOString();
|
||||
await db.prepare(`UPDATE conversation_requests
|
||||
SET status='pending',started_at=NULL
|
||||
WHERE status='processing' AND started_at IS NOT NULL AND started_at<?`)
|
||||
.bind(staleBefore).run();
|
||||
|
||||
const row=await db.prepare(`SELECT id,created_at,speaker_name,message,channel,zone_name,receiver,selected_player,nearby_bots,status,attempts
|
||||
FROM conversation_requests WHERE status='pending' ORDER BY created_at LIMIT 1`).first<any>();
|
||||
if(!row)return null;
|
||||
|
||||
const startedAt=new Date().toISOString();
|
||||
const updated=await db.prepare(`UPDATE conversation_requests
|
||||
SET status='processing',started_at=?,attempts=attempts+1
|
||||
WHERE id=? AND status='pending'`).bind(startedAt,row.id).run();
|
||||
if(updated.meta.changes!==1)return null;
|
||||
|
||||
return {
|
||||
id:row.id,
|
||||
createdAt:row.created_at,
|
||||
speakerName:row.speaker_name,
|
||||
message:row.message,
|
||||
channel:row.channel==='whisper'?'whisper':'say',
|
||||
zoneName:row.zone_name,
|
||||
receiver:row.receiver,
|
||||
selectedPlayer:row.selected_player,
|
||||
nearbyBots:String(row.nearby_bots||'').split(',').map((x:string)=>x.trim()).filter(Boolean),
|
||||
status:'processing',
|
||||
attempts:Number(row.attempts||0)+1
|
||||
};
|
||||
}
|
||||
|
||||
export async function completeConversation(db:D1Database,id:string,result:string){
|
||||
await ensure(db);
|
||||
await db.prepare(`UPDATE conversation_requests
|
||||
SET status='completed',result=?,error=NULL,completed_at=?
|
||||
WHERE id=?`).bind(result.slice(0,2000),new Date().toISOString(),id).run();
|
||||
}
|
||||
|
||||
export async function failConversation(db:D1Database,id:string,error:string){
|
||||
await ensure(db);
|
||||
await db.prepare(`UPDATE conversation_requests
|
||||
SET status='failed',error=?,completed_at=?
|
||||
WHERE id=?`).bind(error.slice(0,2000),new Date().toISOString(),id).run();
|
||||
}
|
||||
|
||||
export async function cleanupConversations(db:D1Database){
|
||||
await ensure(db);
|
||||
const before=new Date(Date.now()-24*60*60_000).toISOString();
|
||||
await db.prepare(`DELETE FROM conversation_requests
|
||||
WHERE status IN ('completed','failed') AND completed_at IS NOT NULL AND completed_at<?`)
|
||||
.bind(before).run();
|
||||
}
|
||||
Reference in New Issue
Block a user