Skip to content

Commit

Permalink
load prompts from globs, provide more information to prompt templates…
Browse files Browse the repository at this point in the history
…, make pseudo-function parsing more flexible, add enter/exit messages to digest system
  • Loading branch information
ssube committed Jun 5, 2024
1 parent 573b15b commit 8a4ecd2
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 44 deletions.
22 changes: 3 additions & 19 deletions prompts/llama-base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,23 +186,7 @@ prompts:
action_check_calendar_each: |
{{name}} will happen in {{turns}} turn
# digest system
digest_action_move: |
{{event.character | name}} entered the room.
digest_action_take: |
{{event.character | name}} picked up the {{event.parameters[item]}}.
digest_action_give: |
{{event.character | name}} gave the {{event.parameters[item]}} to {{event.parameters[character]}}.
digest_action_drop: |
{{event.character | name}} dropped the {{event.parameters[item]}}.
digest_action_ask: |
{{event.character | name}} asked {{event.parameters[character]}} about something.
digest_action_tell: |
{{event.character | name}} told {{event.parameters[character]}} about something.
digest_action_examine: |
{{event.character | name}} examined the {{event.parameters[target]}}.
# world defaults
# default dungeon master
world_default_dungeon_master: |
You are the dungeon master in charge of creating an engaging fantasy world full of interesting characters who
interact with each other and explore their environment. Be creative and original, creating a world that is
Expand Down Expand Up @@ -233,7 +217,7 @@ prompts:
world_generate_room_broadcast_characters: |
Generating {{character_count}} characters for room: {{name}}
world_generate_room_broadcast_portals: |
Generating {{portal_count}} portals for room: {{name}}
Generating {{portal_count}} portals for room: {{room | name}}
world_generate_portal_name_outgoing: |
Generate the name of a portal that leads from the {{source_room}} room to the {{dest_room}} room and fits the world theme of {{world_theme}}.
Expand Down Expand Up @@ -346,7 +330,7 @@ prompts:
# world simulation
world_simulate_character_action: |
You are currently in the {{room_name}} room. {{room_description}}. {{attributes}}.
You are currently in the {{room | name}} room. {{room | describe}}. {{attributes}}.
The room contains the following characters: {{visible_characters}}.
The room contains the following items: {{visible_items}}.
Your inventory contains the following items: {{character_items}}.
Expand Down
24 changes: 24 additions & 0 deletions prompts/llama-digest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
prompts:
# digest system
digest_action_move_other_enter: |
{{event.character | name}} entered the room through the {{source_portal | name}}.
digest_action_move_other_exit: |
{{event.character | name}} left the room, heading through the {{destination_portal | name}}.
digest_action_move_self_enter: |
You entered the room through the {{source_portal | name}}.
digest_action_move_self_exit: |
You left the room, heading through the {{destination_portal | name}}.
digest_action_move: |
{{event.character | name}} entered the room.
digest_action_take: |
{{event.character | name}} picked up the {{event.parameters[item]}}.
digest_action_give: |
{{event.character | name}} gave the {{event.parameters[item]}} to {{event.parameters[character]}}.
digest_action_drop: |
{{event.character | name}} dropped the {{event.parameters[item]}}.
digest_action_ask: |
{{event.character | name}} asked {{event.parameters[character]}} about something.
digest_action_tell: |
{{event.character | name}} told {{event.parameters[character]}} about something.
digest_action_examine: |
{{event.character | name}} examined the {{event.parameters[target]}}.
8 changes: 4 additions & 4 deletions prompts/llama-quest.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
prompts:
action_accept_quest_error_none: No quests are available at the moment.
action_accept_quest_error_name: |
{{character}} does not have a quest named "{{quest_name}}".
{{character}} does not have a quest named "{{quest.name}}".
action_accept_quest_error_room: |
{{character}} is not in the room.
action_accept_quest_result: |
You have started the quest "{{quest_name}}".
You have started the quest "{{quest.name}}".
action_submit_quest_error_active: |
You do not have any active quests.
action_submit_quest_error_none: No quests are available at the moment.
action_submit_quest_error_name: |
{{character}} does not have a quest named "{{quest_name}}".
{{character}} does not have a quest named "{{quest.name}}".
action_submit_quest_error_room: |
{{character}} is not in the room.
action_submit_quest_result: |
You have completed the quest "{{quest_name}}".
You have completed the quest "{{quest.name}}".
5 changes: 3 additions & 2 deletions taleweave/actions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def action_examine(target: str) -> str:
format_prompt(
"action_examine_broadcast_action",
action_character=action_character,
action_room=action_room,
target=target,
)
)
Expand All @@ -49,7 +50,7 @@ def action_examine(target: str) -> str:
action_room=action_room,
)
)
return format_prompt("action_examine_result_room", action_room=action_room)
return format_prompt("action_examine_result_room", target_room=action_room)

target_character = find_character_in_room(action_room, target)
if target_character:
Expand Down Expand Up @@ -118,7 +119,7 @@ def action_move(direction: str) -> str:
format_prompt(
"action_move_error_room",
direction=direction,
destination=portal.destination,
portal=portal,
)
)

Expand Down
4 changes: 2 additions & 2 deletions taleweave/actions/quest.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ def submit_quest(character: str) -> str:
return format_prompt(
"action_submit_quest_result",
character=character,
quest=active_quest.name,
quest=active_quest,
)

return format_prompt(
"action_submit_quest_error_name",
character=character,
quest=active_quest.name,
quest=active_quest,
)
2 changes: 1 addition & 1 deletion taleweave/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ def link_rooms(
format_prompt(
"world_generate_room_broadcast_portals",
portal_count=num_portals,
name=room.name,
room=room,
)
)

Expand Down
8 changes: 8 additions & 0 deletions taleweave/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import atexit
from functools import partial
from glob import glob
from logging.config import dictConfig
from os import environ, path
from typing import List
Expand Down Expand Up @@ -195,7 +196,11 @@ def get_world_prompt(args) -> WorldPrompt:

def load_prompt_library(args) -> None:
if args.prompts:
prompt_files = []
for prompt_file in args.prompts:
prompt_files.extend(glob(prompt_file, recursive=True))

for prompt_file in prompt_files:
with open(prompt_file, "r") as f:
new_library = PromptLibrary(**load_yaml(f))
logger.info(f"loaded prompt library from {prompt_file}")
Expand Down Expand Up @@ -258,6 +263,7 @@ def load_or_generate_world(
llm,
memory_factory=memory_factory,
)
set_dungeon_master(world_builder)

if path.exists(world_state_file):
logger.info(f"loading world state from {world_state_file}")
Expand Down Expand Up @@ -285,6 +291,8 @@ def load_or_generate_world(
systems,
room_count=args.rooms,
)
load_or_initialize_system_data(args, systems, world)

save_world(world, world_file)
save_system_data(args, systems)

Expand Down
17 changes: 12 additions & 5 deletions taleweave/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from taleweave.context import action_context
from taleweave.models.event import PromptEvent
from taleweave.utils import try_parse_float, try_parse_int

logger = getLogger(__name__)

Expand Down Expand Up @@ -122,12 +123,18 @@ def parse_pseudo_function(self, reply: str):
def parse_value(value: str) -> str | bool | float | int:
if value.startswith("~"):
return value[1:]
if value.lower() in ["true", "false"]:
return value.lower() == "true"
if value.isdecimal():
return float(value)
if value.isnumeric():

if value.lower() in ["true", "false", "yes", "no", "y", "n"]:
return value.lower() in ["true", "yes", "y"]

int_value = try_parse_int(value)
if int_value is not None:
return int(value)

float_value = try_parse_float(value)
if float_value is not None:
return float(value)

return value

params = {
Expand Down
5 changes: 2 additions & 3 deletions taleweave/simulate.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
from taleweave.utils.planning import expire_events, get_upcoming_events
from taleweave.utils.prompt import format_prompt
from taleweave.utils.search import find_containing_room
from taleweave.utils.world import describe_entity, format_attributes
from taleweave.utils.world import format_attributes

logger = getLogger(__name__)

Expand Down Expand Up @@ -136,8 +136,7 @@ def result_parser(value, **kwargs):
character_items=character_items,
attributes=character_attributes,
directions=room_directions,
room_name=room.name,
room_description=describe_entity(room),
room=room,
visible_characters=room_characters,
visible_items=room_items,
notes_prompt=notes_prompt,
Expand Down
85 changes: 78 additions & 7 deletions taleweave/systems/digest.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,87 @@
from logging import getLogger
from typing import Dict, List
from typing import Any, Dict, List

from taleweave.context import get_current_world, get_prompt_library, subscribe
from taleweave.game_system import FormatPerspective, GameSystem
from taleweave.models.entity import Character, Room, World, WorldEntity
from taleweave.models.event import ActionEvent, GameEvent
from taleweave.utils.prompt import format_str
from taleweave.utils.search import find_containing_room
from taleweave.utils.search import find_containing_room, find_portal, find_room

logger = getLogger(__name__)


def create_move_digest(
world: World,
active_room: Room,
active_character: Character,
event: ActionEvent,
) -> str:
source_room = event.room
direction = str(event.parameters.get("direction"))
destination_portal = find_portal(world, direction)
if not destination_portal:
raise ValueError(f"Could not find portal for direction {direction}")

destination_room = find_room(world, destination_portal.destination)
if not destination_room:
raise ValueError(
f"Could not find destination room {destination_portal.destination}"
)

# look up the source portal
source_portal = next(
(
portal
for portal in destination_room.portals
if portal.destination == source_room.name
),
None,
)
if not source_portal:
raise ValueError(f"Could not find source portal for {destination_portal.name}")

mode = "self" if (event.character == active_character) else "other"
mood = "enter" if (destination_room == active_room) else "exit"

message = format_str(
f"digest_move_{mode}_{mood}",
destination_portal=destination_portal,
destination_room=destination_room,
direction=direction,
source_portal=source_portal,
source_room=source_room,
)
return message


def create_turn_digest(
active_room: Room, active_character: Character, turn_events: List[GameEvent]
world: World,
active_room: Room,
active_character: Character,
turn_events: List[GameEvent],
) -> List[str]:
library = get_prompt_library()
messages = []
for event in turn_events:
if isinstance(event, ActionEvent):
if event.character == active_character or event.room == active_room:
# special handling for move actions
if event.action == "action_move":
message = create_move_digest(
world, active_room, active_character, event
)
messages.append(message)
elif event.character == active_character or event.room == active_room:
prompt_key = f"digest_{event.action}"
if prompt_key in library.prompts:
try:
template = library.prompts[prompt_key]
message = format_str(template, event=event)
message = format_str(
template,
active_character=active_character,
active_room=active_room,
event=event,
)
messages.append(message)
except Exception:
logger.exception("error formatting digest event: %s", event)
Expand Down Expand Up @@ -65,10 +123,16 @@ def format_digest(
if not room:
raise ValueError("Character not found in any room")

digest = create_turn_digest(room, entity, buffer)
digest = create_turn_digest(world, room, entity, buffer)
return "\n".join(digest)


def generate_digest(agent: Any, theme: str, entity: WorldEntity):
if isinstance(entity, Character):
if entity.name not in character_buffers:
character_buffers[entity.name] = []


def initialize_digest(world: World):
for room in world.rooms:
for character in room.characters:
Expand All @@ -77,4 +141,11 @@ def initialize_digest(world: World):

def init():
subscribe(GameEvent, digest_listener)
return [GameSystem("digest", format=format_digest, initialize=initialize_digest)]
return [
GameSystem(
"digest",
format=format_digest,
generate=generate_digest,
initialize=initialize_digest,
)
]
3 changes: 3 additions & 0 deletions taleweave/utils/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from jinja2 import Environment

from taleweave.context import get_prompt_library

# from taleweave.utils.conversation import summarize_room
from taleweave.utils.string import and_list, or_list
from taleweave.utils.world import describe_entity, name_entity

Expand All @@ -11,6 +13,7 @@
jinja_env = Environment()
jinja_env.filters["describe"] = describe_entity
jinja_env.filters["name"] = name_entity
# jinja_env.filters["summary"] = summarize_room
jinja_env.filters["and_list"] = and_list
jinja_env.filters["or_list"] = or_list

Expand Down
6 changes: 5 additions & 1 deletion taleweave/utils/world.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ def describe_character(
perspective: FormatPerspective = FormatPerspective.SECOND_PERSON,
) -> str:
attribute_descriptions = format_attributes(character, perspective=perspective)
logger.info("describing character: %s, %s", character.name, attribute_descriptions)
logger.info(
"describing character: %s, attributes: '%s'",
character.name,
attribute_descriptions,
)

if perspective == FormatPerspective.SECOND_PERSON:
character_description = character.backstory
Expand Down

0 comments on commit 8a4ecd2

Please sign in to comment.