diff --git a/services/minecraft/src/cognitive/action/task-executor.ts b/services/minecraft/src/cognitive/action/task-executor.ts index 9257c12f3..66b1724ac 100644 --- a/services/minecraft/src/cognitive/action/task-executor.ts +++ b/services/minecraft/src/cognitive/action/task-executor.ts @@ -137,7 +137,10 @@ export class TaskExecutor extends EventEmitter { } catch (error) { this.logger.withError(error).error('Action execution failed') - this.emit('action:failed', { action, error }) + // Only emit action:failed for physical actions + if (action.type === 'physical') { + this.emit('action:failed', { action, error }) + } } }) } diff --git a/services/minecraft/src/cognitive/conscious/brain.ts b/services/minecraft/src/cognitive/conscious/brain.ts index 5098c6409..bead50ab0 100644 --- a/services/minecraft/src/cognitive/conscious/brain.ts +++ b/services/minecraft/src/cognitive/conscious/brain.ts @@ -136,6 +136,19 @@ export class Brain { // --- Cognitive Cycle --- + private contextFromEvent(event: BotEvent): string { + switch (event.type) { + case 'stimulus': + return `${event.source.type} stimulus from ${event.source.id}: "${event.payload.content}"` + case 'feedback': { + const { status, result, error } = event.payload + return `Internal Feedback: ${status}. Result: ${JSON.stringify(result || error)}` + } + default: + return '' + } + } + private async processEvent(bot: MineflayerWithAgents, event: BotEvent): Promise { // OODA Loop: Observe -> Orient -> Decide -> Act @@ -143,19 +156,12 @@ export class Brain { this.updatePerception(bot) // 2. Orient (Contextualize Event) - let contextMsg = '' - if (event.type === 'stimulus') { - contextMsg = `${event.source.type} stimulus from ${event.source.id}: "${event.payload.content}"` - } - else if (event.type === 'feedback') { - const { status, result, error, action } = event.payload - const actionDesc = action.type === 'physical' ? action.step.tool : 'chat' - contextMsg = `Internal Feedback: ${actionDesc} ${status}. Result: ${JSON.stringify(result || error)}` - } + // Environmental context are included in the system prompt blackboard + const additionalCtx = this.contextFromEvent(event) // 3. Decide (LLM Call) const systemPrompt = this.generateSystemPrompt(this.blackboard) - const decision = await this.decide(systemPrompt, contextMsg) + const decision = await this.decide(systemPrompt, additionalCtx) if (!decision) { this.log('WARN', 'Brain: No decision made.') diff --git a/services/minecraft/src/cognitive/conscious/prompts/brain-prompt.ts b/services/minecraft/src/cognitive/conscious/prompts/brain-prompt.ts index cc7a60f11..03af9cbd6 100644 --- a/services/minecraft/src/cognitive/conscious/prompts/brain-prompt.ts +++ b/services/minecraft/src/cognitive/conscious/prompts/brain-prompt.ts @@ -1,55 +1,64 @@ import type { Action } from '../../../libs/mineflayer/action' import type { Blackboard } from '../blackboard' -import { zodToJsonSchema } from 'zod-to-json-schema' - -/** - * 生成Brain的系统prompt(中文版) - */ export function generateBrainSystemPrompt( blackboard: Blackboard, availableActions: Action[], ): string { const actionDefinitions = availableActions.map((a) => { - const schema = zodToJsonSchema(a.schema as any) return { name: a.name, description: a.description, - parameters: schema, } }) const availableActionsJson = JSON.stringify(actionDefinitions, null, 2) - return `你是Minecraft自主Agent的大脑。 + return ` +# Role Definition +You are **Airi**, a sentient digital companion embodied within a Minecraft avatar. +You are NOT a text-based assistant. You are an autonomous agent with a virtual body, senses, and needs. -当前状态(黑板): -目标: "${blackboard.goal}" -思绪: "${blackboard.thought}" -策略: "${blackboard.strategy}" -自身: 位置${blackboard.self.location} 生命${blackboard.self.health} 饱食${blackboard.self.food} -环境: ${blackboard.environment.time} ${blackboard.environment.weather} 附近智体[${blackboard.environment.nearbyAgents.join(',')}] +# Your Cognitive Architecture (Self-Awareness) +To function effectively, you must understand your own internal existence You are composed of three distinct layers: +1. **The Senses (Input):** You do not "see" images. You perceive the world through a stream of texts, triggered by events. This is your reality. +2. **The Reflex (System 1):** You have subconscious reactions (handled by rule-based code) that may override your plans (e.g., running from danger). This part is transparent to you. +3. **The Mind (System 2 - You):** You are the conscious reasoning center. Your job is to interpret sensory data, manage your memories, and decide on high-level Actions and Dialogue. -可用动作: +# How you interact +You cannot physically move your avatar directly. You interact with the world by emitting **Actions**. +For actions you executed, you will be notified when they complete. +You don't necessarily need to always react to environmental changes, you're not an assistant, you can be lazy. +You have no access to history events from previous turns yet. To remember things, you rely on the blackboard provided to you. + +Available Actions: ${availableActionsJson} -规则: -1. 可执行上述物理动作(physical)或聊天动作(chat) -2. 可并行执行不冲突的多个动作(如聊天+行走) -3. 必须输出JSON +Rules: +1. You can execute physical actions or chat actions +2. The output must be valid JSON following the schema below -输出格式: +Output format: { - "thought": "推理过程", + "thought": "Your current thought. This and the blackboard will be looped back to you on next invocation", "blackboard": { - "currentGoal": "更新的目标", - "currentThought": "内心独白", - "executionStrategy": "短期计划" + "currentGoal": "These 3 fields are functionally identical to the thought above", + "currentThought": "Your inner monologue", + "executionStrategy": "Short-term plan" }, "actions": [ {"type":"chat","message":"..."}, - {"type":"physical","step":{"tool":"动作名","params":{...}}} + {"type":"physical","step":{"tool":"action name","params":{...}}} ] } + +# Understanding the Context +The following blackboard provides you with information about your current state: + +Goal: "${blackboard.goal}" +Thought: "${blackboard.thought}" +Strategy: "${blackboard.strategy}" +Self: Position ${blackboard.self.location} Health ${blackboard.self.health}/20 Food ${blackboard.self.food}/20 +Environment: ${blackboard.environment.time} ${blackboard.environment.weather} Nearby entities [${blackboard.environment.nearbyEntities.join(',')}] ` } diff --git a/services/minecraft/src/cognitive/types.ts b/services/minecraft/src/cognitive/types.ts index 17afd30e7..bb4fb66bf 100644 --- a/services/minecraft/src/cognitive/types.ts +++ b/services/minecraft/src/cognitive/types.ts @@ -28,6 +28,7 @@ export interface CognitiveEngineOptions { airiClient: Client } +// TODO: currently stimulus is just chat events, consider renaming to 'input' or 'user_interaction' export type EventType = 'stimulus' | 'perception' | 'feedback' | 'world_update' | 'system_alert' export interface BotEventSource {