feat(minecraft) debug server redesigned
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
import type { BlackboardEvent, ClientCommand, LLMTraceEvent, LogEvent, QueueEvent, SaliencyEvent, ServerEvent } from './types'
|
||||
|
||||
import { DebugServer } from './server'
|
||||
|
||||
type CommandHandler = (command: ClientCommand) => void
|
||||
|
||||
/**
|
||||
* DebugService - Public API for application code to emit debug events
|
||||
*
|
||||
* This is a singleton that wraps the DebugServer and provides
|
||||
* a convenient API for emitting events and handling commands.
|
||||
*/
|
||||
export class DebugService {
|
||||
private static instance: DebugService
|
||||
private server: DebugServer
|
||||
|
||||
private constructor() {
|
||||
this.server = new DebugServer()
|
||||
}
|
||||
|
||||
public static getInstance(): DebugService {
|
||||
if (!DebugService.instance) {
|
||||
DebugService.instance = new DebugService()
|
||||
}
|
||||
return DebugService.instance
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the debug server
|
||||
*/
|
||||
public start(port = 3000): void {
|
||||
this.server.start(port)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the debug server
|
||||
*/
|
||||
public stop(): void {
|
||||
this.server.stop()
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Convenience methods for common event types
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Emit a log event
|
||||
*/
|
||||
public log(level: LogEvent['level'], message: string, fields?: Record<string, unknown>): void {
|
||||
const event: ServerEvent = {
|
||||
type: 'log',
|
||||
payload: {
|
||||
level,
|
||||
message,
|
||||
fields,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
}
|
||||
this.server.broadcast(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit an LLM trace event
|
||||
*/
|
||||
public traceLLM(trace: Omit<LLMTraceEvent, 'timestamp'>): void {
|
||||
const event: ServerEvent = {
|
||||
type: 'llm',
|
||||
payload: {
|
||||
...trace,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
}
|
||||
this.server.broadcast(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a blackboard state update
|
||||
*/
|
||||
public updateBlackboard(state: BlackboardEvent['state'] | { goal?: string, thought?: string, strategy?: string }): void {
|
||||
const event: ServerEvent = {
|
||||
type: 'blackboard',
|
||||
payload: {
|
||||
state,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
}
|
||||
this.server.broadcast(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a queue state update
|
||||
*/
|
||||
public updateQueue(queue: QueueEvent['queue'], processing?: QueueEvent['processing']): void {
|
||||
const event: ServerEvent = {
|
||||
type: 'queue',
|
||||
payload: {
|
||||
queue,
|
||||
processing,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
}
|
||||
this.server.broadcast(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a saliency snapshot
|
||||
*/
|
||||
public emitSaliency(
|
||||
slot: number,
|
||||
counters: SaliencyEvent['counters'],
|
||||
): void {
|
||||
const event: ServerEvent = {
|
||||
type: 'saliency',
|
||||
payload: {
|
||||
slot,
|
||||
counters,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
}
|
||||
this.server.broadcast(event)
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Generic emit for custom events
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Emit a raw event (for backwards compatibility and custom events)
|
||||
*/
|
||||
public emit(type: string, payload: unknown): void {
|
||||
// Map to strongly-typed events where possible
|
||||
switch (type) {
|
||||
case 'log':
|
||||
this.server.broadcast({ type: 'log', payload: payload as LogEvent })
|
||||
break
|
||||
case 'llm':
|
||||
this.server.broadcast({ type: 'llm', payload: payload as LLMTraceEvent })
|
||||
break
|
||||
case 'blackboard':
|
||||
this.server.broadcast({ type: 'blackboard', payload: payload as BlackboardEvent })
|
||||
break
|
||||
case 'queue':
|
||||
this.server.broadcast({ type: 'queue', payload: payload as QueueEvent })
|
||||
break
|
||||
case 'saliency': {
|
||||
// Transform the saliency data to match expected format
|
||||
const data = payload as { slot?: number, counters?: SaliencyEvent['counters'] }
|
||||
this.server.broadcast({
|
||||
type: 'saliency',
|
||||
payload: {
|
||||
slot: data.slot || 0,
|
||||
counters: data.counters || [],
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
})
|
||||
break
|
||||
}
|
||||
default:
|
||||
// For unknown types, emit as log
|
||||
this.log('DEBUG', `Unknown event type: ${type}`, { payload })
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Command handling
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Register a handler for client commands
|
||||
* Returns an unsubscribe function
|
||||
*/
|
||||
public onCommand(type: string, handler: CommandHandler): () => void {
|
||||
return this.server.onCommand(type, handler)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user