load prompts from globs, provide more information to prompt templates, make pseudo-function parsing more flexible, add enter/exit messages to digest system
This commit is contained in:
parent
573b15befb
commit
8a4ecd2588
|
@ -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
|
||||
|
@ -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}}.
|
||||
|
@ -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}}.
|
||||
|
|
|
@ -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]}}.
|
|
@ -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}}".
|
|
@ -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,
|
||||
)
|
||||
)
|
||||
|
@ -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:
|
||||
|
@ -118,7 +119,7 @@ def action_move(direction: str) -> str:
|
|||
format_prompt(
|
||||
"action_move_error_room",
|
||||
direction=direction,
|
||||
destination=portal.destination,
|
||||
portal=portal,
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -523,7 +523,7 @@ def link_rooms(
|
|||
format_prompt(
|
||||
"world_generate_room_broadcast_portals",
|
||||
portal_count=num_portals,
|
||||
name=room.name,
|
||||
room=room,
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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}")
|
||||
|
@ -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}")
|
||||
|
@ -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)
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ from packit.toolbox import Toolbox
|
|||
|
||||
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__)
|
||||
|
||||
|
@ -122,12 +123,18 @@ class BasePlayer:
|
|||
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 = {
|
||||
|
|
|
@ -53,7 +53,7 @@ from taleweave.utils.effect import expire_effects
|
|||
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__)
|
||||
|
||||
|
@ -136,8 +136,7 @@ def prompt_character_action(
|
|||
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,
|
||||
|
|
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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,6 +3,8 @@ from logging import getLogger
|
|||
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
|
||||
|
||||
|
@ -11,6 +13,7 @@ logger = getLogger(__name__)
|
|||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue