feat(api): render_npc_digest — persona/knowledge/moves/utterance
This commit is contained in:
@@ -55,3 +55,57 @@ def render_digest(canon_log: dict) -> str:
|
|||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append("Describe the scene as it is now.")
|
lines.append("Describe the scene as it is now.")
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def render_npc_digest(
|
||||||
|
canon_log: dict,
|
||||||
|
*,
|
||||||
|
persona: str,
|
||||||
|
knowledge: list[str],
|
||||||
|
disposition: int,
|
||||||
|
available_moves: list[str],
|
||||||
|
utterance: str,
|
||||||
|
) -> str:
|
||||||
|
"""User-message digest for the NPC role (§6). Unlike the narrator digest,
|
||||||
|
this deliberately carries the disposition integer (§6 permits it; §7 hides
|
||||||
|
Luck, not disposition) and the closed move vocabulary the NPC may use."""
|
||||||
|
lines: list[str] = []
|
||||||
|
lines.append(f"You are: {persona}")
|
||||||
|
lines.append(
|
||||||
|
f"Your disposition toward the player: {disposition} "
|
||||||
|
f"(-100 hostile, 0 neutral, 100 devoted)."
|
||||||
|
)
|
||||||
|
|
||||||
|
if knowledge:
|
||||||
|
lines.append("")
|
||||||
|
lines.append("What you know (this is ALL you know — do not invent beyond it):")
|
||||||
|
lines += [f"- {k}" for k in knowledge]
|
||||||
|
|
||||||
|
lines.append("")
|
||||||
|
lines.append("Moves you may perform this turn (use ONLY these, as [MOVE: name(args)]):")
|
||||||
|
lines += [f"- {m}" for m in available_moves]
|
||||||
|
|
||||||
|
location = canon_log.get("location", {})
|
||||||
|
lines.append("")
|
||||||
|
lines.append(f"Location: {location.get('name', 'an unknown place')}")
|
||||||
|
|
||||||
|
events = canon_log.get("recent_events", [])
|
||||||
|
if events:
|
||||||
|
lines.append("Recent events:")
|
||||||
|
lines += [f"- {e}" for e in events]
|
||||||
|
|
||||||
|
facts = canon_log.get("established_facts", [])
|
||||||
|
if facts:
|
||||||
|
lines.append("Established facts:")
|
||||||
|
lines += [f"- {f}" for f in facts]
|
||||||
|
|
||||||
|
for quest in canon_log.get("active_quests", []):
|
||||||
|
if quest.get("status") == "active":
|
||||||
|
lines.append(f"Active quest: {quest.get('name', '')} — {quest.get('objective', '')}")
|
||||||
|
|
||||||
|
player = canon_log.get("player", {})
|
||||||
|
lines.append(f"The player is {player.get('name', '')}, a {player.get('class_id', '')}.")
|
||||||
|
|
||||||
|
lines.append("")
|
||||||
|
lines.append(f'The player says to you: "{utterance}"')
|
||||||
|
return "\n".join(lines)
|
||||||
|
|||||||
@@ -40,3 +40,26 @@ def test_narrator_body_is_authored():
|
|||||||
assert "TBD" not in body
|
assert "TBD" not in body
|
||||||
assert "[FACT:" in body # the tag instruction is present
|
assert "[FACT:" in body # the tag instruction is present
|
||||||
assert "second person" in body # the core task is present
|
assert "second person" in body # the core task is present
|
||||||
|
|
||||||
|
|
||||||
|
def test_render_npc_digest_includes_all_sections():
|
||||||
|
from app import prompts
|
||||||
|
log = {
|
||||||
|
"player": {"name": "Aldric", "class_id": "sellsword", "luck_descriptor": "the dice are kind"},
|
||||||
|
"location": {"id": "greywater_docks", "name": "Greywater Docks"},
|
||||||
|
"party": [], "recent_events": ["a gull screamed"],
|
||||||
|
"established_facts": ["the eastern bridge is out"],
|
||||||
|
"active_quests": [], "humiliations": [],
|
||||||
|
}
|
||||||
|
out = prompts.render_npc_digest(
|
||||||
|
log, persona="A harried clerk.", knowledge=["The ledger is gone."],
|
||||||
|
disposition=-10, available_moves=["reveal(varrell_twins)", "refuse"],
|
||||||
|
utterance="What happened here?",
|
||||||
|
)
|
||||||
|
assert "A harried clerk." in out
|
||||||
|
assert "-10" in out
|
||||||
|
assert "The ledger is gone." in out
|
||||||
|
assert "reveal(varrell_twins)" in out
|
||||||
|
assert "Greywater Docks" in out
|
||||||
|
assert "the eastern bridge is out" in out
|
||||||
|
assert out.rstrip().endswith('What happened here?"') # utterance last
|
||||||
|
|||||||
Reference in New Issue
Block a user