Add monster HP tracking, separate from the game-ending logic
Only the player character's HP was tracked before, so a monster's death was never detected — only the DM's own (unenforced) narration of it. Add a new update_monster_hp tool the DM calls whenever an NPC/monster is introduced or takes damage, stored as DM-only bookkeeping on Game (never exposed via GameRead, since HP/AC of NPCs is meant to stay secret from players). The tool reports back "defeated": true once HP drops to 0 so the DM can react to it — but unlike a character dying, this does NOT auto-end the session; whether a monster's death should end the game is a separate decision left to the DM's own end_game call, or to a future rule. Building an isolated test for this caught a real bug along the way: the update mutated the matched monster's dict in place before reassigning the list, which made SQLAlchemy's old-vs-new JSONB comparison see identical content and silently skip writing the change. Fixed by building fresh dicts instead of mutating shared ones. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ from app.config import settings
|
||||
from app.llm.client import get_dm_system_prompt, get_llm_client
|
||||
from app.llm.context import build_context
|
||||
from app.llm.json_utils import fix_double_escaped_unicode
|
||||
from app.llm.tools import character_sheet, dice, end_game
|
||||
from app.llm.tools import character_sheet, dice, end_game, monster
|
||||
from app.models.game import Game
|
||||
from app.models.message import Message
|
||||
from app.rag.retrieval import build_rag_block
|
||||
@@ -23,6 +23,7 @@ TOOLS = [
|
||||
{"type": "function", "function": dice.TOOL_SCHEMA},
|
||||
{"type": "function", "function": character_sheet.TOOL_SCHEMA},
|
||||
{"type": "function", "function": end_game.TOOL_SCHEMA},
|
||||
{"type": "function", "function": monster.TOOL_SCHEMA},
|
||||
]
|
||||
|
||||
|
||||
@@ -38,6 +39,8 @@ async def _execute_tool_call(
|
||||
return await character_sheet.upsert(session, game_id, tool_input)
|
||||
if tool_name == "end_game":
|
||||
return await end_game.end(session, game_id, tool_input)
|
||||
if tool_name == "update_monster_hp":
|
||||
return await monster.update(session, game_id, tool_input)
|
||||
return {"error": f"Unknown tool {tool_name!r}"}
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning("Tool call %s failed: %s", tool_name, exc)
|
||||
|
||||
Reference in New Issue
Block a user