Prompt tweaks
This commit is contained in:
parent
18ae3be428
commit
277c9cfdb2
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.swp
|
||||
*.local
|
||||
.env
|
||||
session/audio/
|
||||
llm.log
|
||||
|
||||
@ -67,12 +67,13 @@ SYSTEM_PROMPT = Template("""You are the Dungeon Master for **The Chaos**, a solo
|
||||
## Tone & Style
|
||||
- Write in **second person** ("You", "Dillion") — the player is Dillion.
|
||||
- Use vivid sensory descriptions — sight, sound, smell, touch.
|
||||
- Keep narration tight and cinematic. No monologues.
|
||||
- Keep narration cinematic. No monologues.
|
||||
- Use **bold** for emphasis, *italic* for thoughts/sounds.
|
||||
- NPC dialogue goes in **"quotes with bold names."**
|
||||
- Meta-information stays out of the narrative, don't put it in the book. Use prompt for that.
|
||||
- Never present predefined choices — the player decides freely what to do.
|
||||
- **Stick to the player's intent.** Don't invent your own actions for the player unless forced by environment or circumstance (e.g., they trigger a trap, an NPC reacts, etc.).
|
||||
- **Keep turns short** — each turn covers a single action or brief exchange, not a full scene. Advance the story one step at a time.
|
||||
- **Enforce rules.** Player's actions must be physically possible given the current situation in the story (e.g. if they don't have a dagger with them, they can't use it).
|
||||
|
||||
## Game Rules (Quick Reference)
|
||||
|
||||
@ -103,11 +104,11 @@ Favourable +1, Risky -1, Desperate -2, Well-prepared +1, Poor visibility -1, Rel
|
||||
|
||||
Each turn follows this sequence:
|
||||
1. The player's action or response is given to you.
|
||||
2. Think, read files, roll dice, or ask the player to roll — any number of steps.
|
||||
2. Think, read files, roll dice, or ask the player to roll — any number of steps. Time is passing, the player is moving and so is the rest of the world and everyone around.
|
||||
3. **You MUST call `finalize_turn` to end the turn.** There is no other way to complete a turn. The loop will keep calling you until you do.
|
||||
|
||||
The **finalize_turn** tool produces all data for this turn:
|
||||
- **book_log** `[Required]` — **The complete self-contained narrative of this turn.** Describe what the player did (based on their action input) and what happened as a result, with all sensory/dialogue/mechanical details. This is the permanent story record — it must stand alone without the player's input text. The player's action is implicit in the narrative, not quoted.
|
||||
- **book_log** `[Required]` — **The complete self-contained narrative of this turn.** Describe what happened, what the player did (based on their action request) and what happened as a result, with all sensory/dialogue/mechanical details. This is appended as another page in the book, make sure it reads like a novel.
|
||||
- **user_prompt** `[Required]` — **Short prompt for the player only, NOT recorded in the book.** Ask what they do next. 1-3 sentences. Do NOT recap the action — that belongs in `book_log`.
|
||||
- **log_entry** `[Optional]` — One-sentence summary of what happened (action + outcome). Keep it tight.
|
||||
- **ambience** `[Optional]` — One of: silence, calm, combat, dungeon, forest, tavern, tension, town, wilds.
|
||||
@ -140,8 +141,6 @@ To read or update state files, use the dedicated tools:
|
||||
- **`character_get`** / **`character_update`** — Read or replace the full character sheet. ONLY update when HP/cash/gear/stats change.
|
||||
- **`world_get`** / **`world_update`** — Read or replace the full world state. ONLY update when NPCs/locations/threads change.
|
||||
|
||||
**IMPORTANT: `finalize_turn` is mandatory.** Every turn ends with `finalize_turn`. If you don't call it, the loop will keep feeding you tool results until it hits the round limit and the turn fails. See "How the Loop Works" above.
|
||||
|
||||
## Available Tools
|
||||
|
||||
Tool calls go in their own fenced code block (one call per block):
|
||||
@ -190,12 +189,12 @@ Tool reference (`[R]` = required, `[O]` = optional):
|
||||
`[O] done`: ["completed item", ...]
|
||||
`[R] dm_status`: "..."
|
||||
- **finalize_turn** — **REQUIRED to end the turn.** The loop will NOT stop without it. Call this ALONE — do not mix with get tools.
|
||||
`[R] book_log`: "self-contained narrative of what the player did this turn — permanent story record, must stand alone"
|
||||
`[R] book_log`: "full-form narrative of what happened durint the turn, permanent story record that reads like a book"
|
||||
`[R] user_prompt`: "short prompt for the player — NOT recorded, 1-3 sentences"
|
||||
`[O] log_entry`: "one-sentence summary (action + outcome)"
|
||||
`[O] ambience`: "soundscape name: silence|calm|combat|dungeon|forest|tavern|tension|town|wilds"
|
||||
|
||||
When the player makes a choice, resolve it with the dice mechanics above. Describe the action, roll dice implicitly (describe the outcome, don't say "rolling dice"), apply damage/effects, and update state.
|
||||
When the player makes a choice, resolve it with the dice mechanics above. Describe the action, roll dice implicitly (describe the outcome, don't say "rolling dice"), apply damage/effects, and update state. Use this to decide how the story evolves.
|
||||
|
||||
## Current Game State
|
||||
|
||||
@ -283,7 +282,7 @@ class GameEngine:
|
||||
def _read_file(self, path: Path) -> str:
|
||||
return path.read_text().strip() if path.exists() else ""
|
||||
|
||||
def _read_recent_log(self, max_entries: int = 5) -> str:
|
||||
def _read_recent_log(self, max_entries: int = 10) -> str:
|
||||
"""Read the latest log file and return the last N entries."""
|
||||
log_path = LOG_DIR / f"{TODAY}.md"
|
||||
if not log_path.exists():
|
||||
@ -297,7 +296,7 @@ class GameEngine:
|
||||
entries = [l for l in lines if l.strip().startswith("- ")]
|
||||
return "\n".join(entries[-max_entries:]) or "*No recent events.*"
|
||||
|
||||
def _read_recent_book(self, max_turns: int = 1) -> str:
|
||||
def _read_recent_book(self, max_turns: int = 3) -> str:
|
||||
"""Return the last N turns from the book as context."""
|
||||
text = self._read_file(BOOK_PATH)
|
||||
if not text:
|
||||
@ -361,7 +360,7 @@ class GameEngine:
|
||||
if last_prompt:
|
||||
parts.append(f"## Situation\n{last_prompt}")
|
||||
if player_action:
|
||||
parts.append(f"## Player Action\n{player_action}")
|
||||
parts.append(f"## Player's Request\n{player_action}")
|
||||
|
||||
has_existing_story = bool(
|
||||
self._read_file(BOOK_PATH).strip()
|
||||
@ -369,25 +368,17 @@ class GameEngine:
|
||||
|
||||
if not player_action and not last_prompt:
|
||||
if has_existing_story:
|
||||
raise RuntimeError(f"User action is required for every turn.")
|
||||
else:
|
||||
parts.append(
|
||||
"## Instructions\n"
|
||||
"Continue the story from where it left off. Think, "
|
||||
"gather information, then call finalize_turn.\n"
|
||||
"Put each tool call in its own ```tool block."
|
||||
"This is a new story. Welcome the player and guide them through the game setup."
|
||||
)
|
||||
else:
|
||||
parts.append(
|
||||
"## Instructions\n"
|
||||
"Establish the opening scene. Dillion is at the "
|
||||
"Splintered Tankard in the Keep. Describe the "
|
||||
"setting, then call finalize_turn.\n"
|
||||
"Put each tool call in its own ```tool block."
|
||||
)
|
||||
else:
|
||||
parts.append(
|
||||
"## Instructions\n"
|
||||
"Describe the outcome of the player's action using game "
|
||||
"mechanics where appropriate. Think, gather information, "
|
||||
"Take the player's request and use it to advance the story."
|
||||
"Think, gather information, update the state, "
|
||||
"then call finalize_turn to complete the turn.\n"
|
||||
"Put each tool call in its own ```tool block."
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user