refactor(minecraft): migrate from EventManager to unified EventBus for perception signals
This commit is contained in:
@@ -45,14 +45,14 @@ describe('brain decide retry', () => {
|
||||
} as any
|
||||
|
||||
const brain = new Brain({
|
||||
eventManager: {} as any,
|
||||
eventBus: { subscribe: vi.fn() } as any,
|
||||
neuri,
|
||||
logger,
|
||||
taskExecutor: { getAvailableActions: () => [] } as any,
|
||||
reflexManager: { getContextSnapshot: () => ({}) } as any,
|
||||
})
|
||||
|
||||
; (brain as any).bot = { bot: { chat: vi.fn() } }
|
||||
; (brain as any).bot = { bot: { chat: vi.fn() } }
|
||||
|
||||
const res = await (brain as any).decide('sys', 'user')
|
||||
expect(res?.thought).toBe('ok')
|
||||
@@ -77,7 +77,7 @@ describe('brain decide retry', () => {
|
||||
} as any
|
||||
|
||||
const brain = new Brain({
|
||||
eventManager: {} as any,
|
||||
eventBus: { subscribe: vi.fn() } as any,
|
||||
neuri,
|
||||
logger,
|
||||
taskExecutor: { getAvailableActions: () => [] } as any,
|
||||
@@ -85,7 +85,7 @@ describe('brain decide retry', () => {
|
||||
})
|
||||
|
||||
const chat = vi.fn()
|
||||
; (brain as any).bot = { bot: { chat } }
|
||||
; (brain as any).bot = { bot: { chat } }
|
||||
|
||||
await expect((brain as any).decide('sys', 'user')).rejects.toThrow('unauthorized')
|
||||
expect(neuri.handleStateless).toHaveBeenCalledTimes(1)
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Neuri } from 'neuri'
|
||||
|
||||
import type { TaskExecutor } from '../action/task-executor'
|
||||
import type { ActionInstruction } from '../action/types'
|
||||
import type { EventManager } from '../perception/event-manager'
|
||||
import type { EventBus, TracedEvent } from '../os'
|
||||
import type { PerceptionSignal } from '../perception/types/signals'
|
||||
import type { ReflexManager } from '../reflex/reflex-manager'
|
||||
import type { BotEvent, MineflayerWithAgents } from '../types'
|
||||
@@ -82,7 +82,7 @@ function isLikelyRecoverableError(err: unknown): boolean {
|
||||
}
|
||||
|
||||
interface BrainDeps {
|
||||
eventManager: EventManager
|
||||
eventBus: EventBus
|
||||
neuri: Neuri
|
||||
logger: Logg
|
||||
taskExecutor: TaskExecutor
|
||||
@@ -161,10 +161,7 @@ export class Brain {
|
||||
this.bot = bot
|
||||
this.blackboard.update({ selfUsername: bot.username })
|
||||
|
||||
// Perception Signal Handler - Only process chat messages for now
|
||||
this.deps.eventManager.on<PerceptionSignal>('perception', async (event) => {
|
||||
const signal = event.payload
|
||||
// Only handle chat messages in the deliberative layer
|
||||
const handleSignal = async (signal: PerceptionSignal) => {
|
||||
if (signal.type !== 'chat_message' && signal.type !== 'social_presence')
|
||||
return
|
||||
|
||||
@@ -172,8 +169,17 @@ export class Brain {
|
||||
await this.handlePerceptionSignal(bot, signal)
|
||||
}
|
||||
catch (err) {
|
||||
this.log('ERROR', `Brain: Failed to enqueue chat event`, { error: err })
|
||||
this.log('ERROR', 'Brain: Failed to enqueue chat event', { error: err })
|
||||
}
|
||||
}
|
||||
|
||||
// Perception Signal Handler - unified on EventBus
|
||||
this.deps.eventBus.subscribe<PerceptionSignal>('signal:chat_message', (event: TracedEvent<PerceptionSignal>) => {
|
||||
void handleSignal(event.payload)
|
||||
})
|
||||
|
||||
this.deps.eventBus.subscribe<PerceptionSignal>('signal:social_presence', (event: TracedEvent<PerceptionSignal>) => {
|
||||
void handleSignal(event.payload)
|
||||
})
|
||||
|
||||
// Listen to Task Execution Events (Action Feedback)
|
||||
|
||||
@@ -12,7 +12,6 @@ import { PlanningAgentImpl } from '../agents/planning'
|
||||
import { TaskExecutor } from './action/task-executor'
|
||||
import { Brain } from './conscious/brain'
|
||||
import { createEventBus, createRuleEngine } from './os'
|
||||
import { EventManager } from './perception/event-manager'
|
||||
import { PerceptionPipeline } from './perception/pipeline'
|
||||
import { ReflexManager } from './reflex/reflex-manager'
|
||||
|
||||
@@ -24,7 +23,6 @@ export interface ContainerServices {
|
||||
planningAgent: PlanningAgentImpl
|
||||
chatAgent: ChatAgentImpl
|
||||
neuri: Neuri
|
||||
eventManager: EventManager
|
||||
perceptionPipeline: PerceptionPipeline
|
||||
taskExecutor: TaskExecutor
|
||||
brain: Brain
|
||||
@@ -102,8 +100,6 @@ export function createAgentContainer(options: {
|
||||
idleTimeout: 5 * 60 * 1000, // 5 minutes
|
||||
})),
|
||||
|
||||
eventManager: asClass(EventManager).singleton(),
|
||||
|
||||
perceptionPipeline: asClass(PerceptionPipeline).singleton(),
|
||||
|
||||
taskExecutor: asClass(TaskExecutor).singleton(),
|
||||
@@ -112,6 +108,7 @@ export function createAgentContainer(options: {
|
||||
.singleton()
|
||||
.inject((c) => {
|
||||
return {
|
||||
eventBus: c.resolve('eventBus'),
|
||||
reflexManager: c.resolve('reflexManager'),
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -5,7 +5,6 @@ import { config } from '../composables/config'
|
||||
import { DebugService } from '../debug'
|
||||
import { ChatMessageHandler } from '../libs/mineflayer'
|
||||
import { createAgentContainer } from './container'
|
||||
import { createPerceptionFrameFromChat } from './perception/frame'
|
||||
import { computeNearbyPlayerGaze } from './reflex/gaze'
|
||||
|
||||
export function CognitiveEngine(options: CognitiveEngineOptions): MineflayerPlugin {
|
||||
@@ -24,7 +23,6 @@ export function CognitiveEngine(options: CognitiveEngineOptions): MineflayerPlug
|
||||
const actionAgent = container.resolve('actionAgent')
|
||||
const chatAgent = container.resolve('chatAgent')
|
||||
const perceptionPipeline = container.resolve('perceptionPipeline')
|
||||
const eventManager = container.resolve('eventManager')
|
||||
const brain = container.resolve('brain')
|
||||
const reflexManager = container.resolve('reflexManager')
|
||||
const taskExecutor = container.resolve('taskExecutor')
|
||||
@@ -75,16 +73,6 @@ export function CognitiveEngine(options: CognitiveEngineOptions): MineflayerPlug
|
||||
// Resolve EventBus and subscribe to forward events to debug timeline
|
||||
const eventBus = container.resolve('eventBus')
|
||||
|
||||
// Bridge selected EventBus signals into EventManager perception stream for Brain.
|
||||
eventBus.subscribe('signal:social_presence', (event) => {
|
||||
eventManager.emit({
|
||||
type: 'perception',
|
||||
payload: event.payload as any,
|
||||
source: { type: 'minecraft', id: 'eventBus' },
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
})
|
||||
|
||||
eventBus.subscribe('*', (event) => {
|
||||
// Forward to debug service for timeline visualization
|
||||
DebugService.getInstance().emitTrace({
|
||||
@@ -98,14 +86,13 @@ export function CognitiveEngine(options: CognitiveEngineOptions): MineflayerPlug
|
||||
})
|
||||
})
|
||||
|
||||
// Set message handling via EventManager
|
||||
// Set message handling via EventBus
|
||||
const chatHandler = new ChatMessageHandler(bot.username)
|
||||
bot.bot.on('chat', (username, message) => {
|
||||
if (chatHandler.isBotMessage(username))
|
||||
return
|
||||
|
||||
// Bridge chat directly into EventBus as a signal so Reflex can react to it.
|
||||
// (PerceptionPipeline will also ingest this for Brain via EventManager.)
|
||||
eventBus.emit({
|
||||
type: 'signal:chat_message',
|
||||
payload: Object.freeze({
|
||||
@@ -125,7 +112,7 @@ export function CognitiveEngine(options: CognitiveEngineOptions): MineflayerPlug
|
||||
},
|
||||
})
|
||||
|
||||
perceptionPipeline.ingest(createPerceptionFrameFromChat(username, message))
|
||||
// Chat is handled via signal:chat_message only; no extra perception emission needed.
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import type { BotEvent, EventCategory } from '../types'
|
||||
|
||||
import EventEmitter from 'eventemitter3'
|
||||
|
||||
export class EventManager {
|
||||
private emitter = new EventEmitter()
|
||||
|
||||
public emit<T>(event: BotEvent<T>): void {
|
||||
// TODO: Temporal Context tracking
|
||||
// TODO: Salience Detection / Filtering noise
|
||||
|
||||
if (!event.priority) {
|
||||
event.priority = 0 // Default priority
|
||||
}
|
||||
|
||||
this.emitter.emit(event.type, event)
|
||||
this.emitter.emit('*', event)
|
||||
}
|
||||
|
||||
public on<T>(type: EventCategory | '*', handler: (event: BotEvent<T>) => void): void {
|
||||
this.emitter.on(type, handler)
|
||||
}
|
||||
|
||||
public off<T>(type: EventCategory | '*', handler: (event: BotEvent<T>) => void): void {
|
||||
this.emitter.off(type, handler)
|
||||
}
|
||||
|
||||
public once<T>(type: EventCategory | '*', handler: (event: BotEvent<T>) => void): void {
|
||||
this.emitter.once(type, handler)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ import type { Logg } from '@guiiai/logg'
|
||||
|
||||
import type { EventBus } from '../os'
|
||||
import type { MineflayerWithAgents } from '../types'
|
||||
import type { EventManager } from './event-manager'
|
||||
import type { PerceptionFrame } from './frame'
|
||||
import type { RawPerceptionEvent } from './types/raw-events'
|
||||
import type { PerceptionSignal } from './types/signals'
|
||||
@@ -29,7 +28,6 @@ export class PerceptionPipeline {
|
||||
constructor(
|
||||
private readonly deps: {
|
||||
eventBus: EventBus
|
||||
eventManager: EventManager
|
||||
logger: Logg
|
||||
},
|
||||
) {
|
||||
@@ -96,33 +94,6 @@ export class PerceptionPipeline {
|
||||
{
|
||||
name: 'router',
|
||||
handle: (frame) => {
|
||||
if (frame.kind === 'chat_raw') {
|
||||
const raw = frame.raw as { username: string, message: string }
|
||||
|
||||
// Convert chat to PerceptionSignal
|
||||
const signal: PerceptionSignal = {
|
||||
type: 'chat_message',
|
||||
description: `Chat from ${raw.username}: "${raw.message}"`,
|
||||
sourceId: raw.username,
|
||||
timestamp: Date.now(),
|
||||
confidence: 1.0,
|
||||
metadata: {
|
||||
username: raw.username,
|
||||
message: raw.message,
|
||||
},
|
||||
}
|
||||
|
||||
this.deps.eventManager.emit<PerceptionSignal>({
|
||||
type: 'perception',
|
||||
payload: signal,
|
||||
source: {
|
||||
type: 'minecraft',
|
||||
id: raw.username,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
}
|
||||
|
||||
// Emit all perception signals centrally as BotEvents
|
||||
for (const signalWrapper of frame.signals) {
|
||||
if (signalWrapper.type !== 'perception_signal')
|
||||
@@ -130,11 +101,10 @@ export class PerceptionPipeline {
|
||||
|
||||
const signal = signalWrapper.payload as PerceptionSignal
|
||||
|
||||
this.deps.eventManager.emit<PerceptionSignal>({
|
||||
this.deps.eventBus.emit<PerceptionSignal>({
|
||||
type: 'perception',
|
||||
payload: signal,
|
||||
source: { type: 'minecraft', id: 'perception' },
|
||||
timestamp: Date.now(),
|
||||
source: { component: 'perception', id: 'perception' },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user