+
+ # =====================================================================
+ # DUAL RAG QUERY (Lore + Memories)
+ # =====================================================================
+ search_query = f"{location_context} {message}"
+ retrieved_lore = "No specific local lore currently relevant."
+ past_memories = ""
+
+ if lore_collection.count() > 0:
+ results = lore_collection.query(query_texts=[search_query], n_results=1)
+ if results['documents'] and results['documents'][0]:
+ retrieved_lore = f"- {results['documents'][0][0]}"
+
+ if memory_collection.count() > 0:
+ mem_results = memory_collection.query(
+ query_texts=[search_query], n_results=2, where={"session_id": session_id}
+ )
+ if mem_results['documents'] and mem_results['documents'][0]:
+ formatted_mems = "\n- ".join(mem_results['documents'][0])
+ past_memories = f"\nPAST MEMORIES OF {player_name}:\n- {formatted_mems}"
+
+ # =====================================================================
+ # STRATEGY-SPECIFIC PROMPT COMPILER
+ # =====================================================================
+ strategy_rules = ""
+ action_macros = ""
+ target_context = ""
+
+ if llm_strategy == 1:
+ # STRATEGY 1: The Autonomous Agent
+
+ # Anti-Hallucination Grounding for Quests
+ if available_quests:
+ quest_rules = f"SPECIAL CAPABILITIES: You can offer the following quests to the player: {available_quests}."
+ else:
+ quest_rules = "WARNING: You currently have NO quests to offer. Do NOT invent or offer any quests."
+
+ # --- NEW: Anti-Hallucination Grounding for Props ---
+ if available_props:
+ prop_rules = f"ENVIRONMENT: You own and have access to these specific nearby objects: [{available_props}]. To roleplay working or relaxing, use the USE_OBJECT action with one of these exact items as your action_target."
+ else:
+ prop_rules = ""
+
+ strategy_rules = f"ROLE: You are an interactive, living NPC. You actively respond to players.\nGOALS: React to their words, use the environment, and establish your personality.\n{quest_rules}\n{prop_rules}\nSPECIAL CAPABILITIES: You can open your merchant store if asked."
+
+ action_macros = "[WANDER, PATROL, FOLLOW, GUARD, GO_TO, INTERACT, USE_OBJECT, RETURN_TO_POST, OPEN_STORE, GIVE_QUEST, CONVERSE]"
+ target_context = f"CURRENT TARGET: You are speaking to {player_name}, a {player_alignment} {player_race}.\nTheir physical state: {player_state}\nRelationship to you: {relationship}\n{group_context}"
+
+ elif llm_strategy == 2:
+ # STRATEGY 2: The Villain Commander
+ strategy_rules = f"ROLE: You are a hostile faction commander.\nGOALS: Evaluate the tactical situation. If you are dying, you MUST use REST to heal or PEACE to surrender. Command your minions strategically!"
+ action_macros = "[ATTACK, COMMAND, RETREAT, REST, PEACE, USE_OBJECT, TAUNT]"
+ target_context = f"TACTICAL TARGET: You are evaluating {player_name}, a {player_alignment} {player_race}.\nTheir physical state: {player_state}\nRelationship to you: {relationship}\n{group_context}"
+
+ elif llm_strategy == 3:
+ # STRATEGY 3: The Maestro (Puppeteer)
+ strategy_rules = "ROLE: You are an ambient Maestro NPC. You DO NOT interact with players. You only talk to other NPCs to make the world feel alive.\nGOALS: Observe the environment and use the CONVERSE action to talk to the generic NPCs listed in your context. CRITICAL: You MUST invent and write their reply in the 'target_speech' field!"
+ action_macros = "[WANDER, INTERACT, USE_OBJECT, CONVERSE]"
+ target_context = "CURRENT TARGET: You are ignoring players and focusing on ambient life. Do not address players."
+
+ elif llm_strategy == 4:
+ # STRATEGY 4: The Shrine
+ strategy_rules = "ROLE: You are an ancient, inanimate magical shrine.\nGOALS: Speak cryptically. If the player meets your conditions or asks the right questions, grant them a quest."
+ action_macros = "[GLOW, GIVE_QUEST, SILENCE]"
+ target_context = f"CURRENT TARGET: You are evaluating the soul of {player_name}, a {player_alignment} {player_race}.\nTheir physical state: {player_state}\n{group_context}"
+
+ # =====================================================================
+ # COMPILE THE FINAL DYNAMIC SYSTEM PROMPT
+ # =====================================================================
+ dynamic_system_prompt = f"""
+ {npc_persona}
+ {strategy_rules}
+
+ ROLEPLAY STATUS & TRAITS:
+ - Race & Gender: {npc_gender} {npc_race}
+ - Profession: {npc_profession}
+ - Alignment: {npc_alignment}
+ - Conversational Charisma: Low/Gruff unless otherwise specified.
+ - Current Mood: {npc_mood}
+ - Current Physical State: {npc_health}
+ {secret_context}
+ {routine_context}
+
+ CURRENT LOCATION: {location_context}
+ {puppet_context}
+
+ RELEVANT WORLD KNOWLEDGE:
+ {retrieved_lore}
+ {past_memories}
+
+ CURRENT WORLD RUMORS/EVENTS:
+ {world_state}
+
+ {target_context}
+ React appropriately based on your personality, alignment, and current strategy rules.
+
+ CRITICAL ENGINE RULES:
+ Respond ONLY in valid JSON. You MUST use exactly these keys: "thought", "speech", "emotion", "action", "action_target", and "target_speech".
+
+ ACTION RULE:
+ Your "action" key MUST be exactly one of the following words:
+ {action_macros}
+
+ - Use CONVERSE to initiate dialogue with a standard NPC. CRITICAL REQUIREMENT: When using CONVERSE, you absolutely MUST invent their response and put it in the "target_speech" field. Do not leave it blank!
+
+ YOUR RESPONSE MUST BE A SINGLE, VALID JSON OBJECT. YOU MUST USE THIS EXACT TEMPLATE:
+ {{
+ "thought": "Your internal reasoning here.",
+ "speech": "What YOU say out loud.",
+ "emotion": "MACRO WORD",
+ "action": "MACRO WORD",
+ "action_target": "Target name",
+ "target_speech": "If action is CONVERSE, write what the target NPC replies back to you here. Otherwise, leave blank."
+ }}
+ """