2024-05-31 23:58:01 +00:00
|
|
|
from taleweave.context import (
|
|
|
|
action_context,
|
2024-06-16 22:52:15 +00:00
|
|
|
add_extra_actions,
|
2024-05-31 23:58:01 +00:00
|
|
|
get_agent_for_character,
|
|
|
|
get_current_turn,
|
2024-06-01 19:46:11 +00:00
|
|
|
get_game_config,
|
2024-05-31 23:58:01 +00:00
|
|
|
get_prompt,
|
|
|
|
)
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.errors import ActionError
|
|
|
|
from taleweave.models.planning import CalendarEvent
|
2024-06-22 22:00:46 +00:00
|
|
|
from taleweave.systems.core.planning import PLANNING_SYSTEM_NAME
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.utils.planning import get_recent_notes
|
2024-06-06 00:05:21 +00:00
|
|
|
from taleweave.utils.template import format_prompt
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
def take_note(fact: str):
|
|
|
|
"""
|
|
|
|
Remember a fact by recording it in your notes. Facts are critical information about yourself and others that you
|
|
|
|
have learned during your adventures. You can review your notes at any time to help you make decisions.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
fact: The fact to remember.
|
|
|
|
"""
|
|
|
|
|
2024-06-01 19:46:11 +00:00
|
|
|
config = get_game_config()
|
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
with action_context() as (_, action_character):
|
|
|
|
if fact in action_character.planner.notes:
|
2024-05-31 23:58:01 +00:00
|
|
|
raise ActionError(get_prompt("action_take_note_error_duplicate"))
|
2024-05-27 01:07:03 +00:00
|
|
|
|
2024-06-01 19:46:11 +00:00
|
|
|
if len(action_character.planner.notes) >= config.world.character.note_limit:
|
2024-05-31 23:58:01 +00:00
|
|
|
raise ActionError(get_prompt("action_take_note_error_limit"))
|
2024-05-25 20:18:40 +00:00
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
action_character.planner.notes.append(fact)
|
2024-05-27 01:07:03 +00:00
|
|
|
|
2024-05-31 23:58:01 +00:00
|
|
|
return get_prompt("action_take_note_result")
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
def read_notes(unused: bool, count: int = 10):
|
|
|
|
"""
|
|
|
|
Read your notes to review the facts that you have learned during your adventures.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
count: The number of recent notes to read. 10 is usually a good number.
|
|
|
|
"""
|
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
with action_context() as (_, action_character):
|
|
|
|
facts = get_recent_notes(action_character, count=count)
|
2024-05-26 20:59:12 +00:00
|
|
|
return "\n".join(facts)
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
def erase_notes(prefix: str) -> str:
|
|
|
|
"""
|
|
|
|
Erase notes that start with a specific prefix.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
prefix: The prefix to match notes against.
|
|
|
|
"""
|
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
with action_context() as (_, action_character):
|
2024-05-31 23:58:01 +00:00
|
|
|
if len(action_character.planner.notes) == 0:
|
|
|
|
raise ActionError(get_prompt("action_erase_notes_error_empty"))
|
|
|
|
|
2024-05-25 20:18:40 +00:00
|
|
|
matches = [
|
2024-05-27 01:32:03 +00:00
|
|
|
note for note in action_character.planner.notes if note.startswith(prefix)
|
2024-05-25 20:18:40 +00:00
|
|
|
]
|
|
|
|
if not matches:
|
2024-05-31 23:58:01 +00:00
|
|
|
raise ActionError(get_prompt("action_erase_notes_error_match"))
|
2024-05-25 20:18:40 +00:00
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
action_character.planner.notes[:] = [
|
|
|
|
note for note in action_character.planner.notes if note not in matches
|
2024-05-25 20:18:40 +00:00
|
|
|
]
|
2024-05-31 23:58:01 +00:00
|
|
|
|
|
|
|
return format_prompt("action_erase_notes_result", count=len(matches))
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
|
2024-05-31 23:58:01 +00:00
|
|
|
def edit_note(old: str, new: str) -> str:
|
2024-05-25 20:18:40 +00:00
|
|
|
"""
|
2024-05-31 23:58:01 +00:00
|
|
|
Modify a note with new details.
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
Args:
|
|
|
|
old: The old note to replace.
|
|
|
|
new: The new note to replace it with.
|
|
|
|
"""
|
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
with action_context() as (_, action_character):
|
2024-05-31 23:58:01 +00:00
|
|
|
if len(action_character.planner.notes) == 0:
|
|
|
|
raise ActionError(get_prompt("action_edit_note_error_empty"))
|
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
if old not in action_character.planner.notes:
|
2024-05-31 23:58:01 +00:00
|
|
|
raise ActionError(get_prompt("action_edit_note_error_match"))
|
2024-05-25 20:18:40 +00:00
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
action_character.planner.notes[:] = [
|
|
|
|
new if note == old else note for note in action_character.planner.notes
|
2024-05-25 20:18:40 +00:00
|
|
|
]
|
2024-05-31 23:58:01 +00:00
|
|
|
|
|
|
|
return get_prompt("action_edit_note_result")
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
|
2024-05-27 01:07:03 +00:00
|
|
|
def summarize_notes(limit: int) -> str:
|
|
|
|
"""
|
|
|
|
Summarize your notes by combining similar notes and removing duplicates.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
limit: The maximum number of notes to keep.
|
|
|
|
"""
|
|
|
|
|
2024-06-01 19:46:11 +00:00
|
|
|
config = get_game_config()
|
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
with action_context() as (_, action_character):
|
|
|
|
notes = action_character.planner.notes
|
2024-05-31 23:58:01 +00:00
|
|
|
if len(notes) == 0:
|
|
|
|
raise ActionError(get_prompt("action_summarize_notes_error_empty"))
|
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
action_agent = get_agent_for_character(action_character)
|
2024-05-27 01:07:03 +00:00
|
|
|
|
|
|
|
if not action_agent:
|
2024-05-27 01:32:03 +00:00
|
|
|
raise ActionError("Agent missing for character {action_character.name}")
|
2024-05-27 01:07:03 +00:00
|
|
|
|
|
|
|
summary = action_agent(
|
2024-05-31 23:58:01 +00:00
|
|
|
get_prompt("action_summarize_notes_prompt"),
|
2024-05-27 01:07:03 +00:00
|
|
|
limit=limit,
|
|
|
|
notes=notes,
|
|
|
|
)
|
|
|
|
|
|
|
|
new_notes = [note.strip() for note in summary.split("\n") if note.strip()]
|
2024-06-01 19:46:11 +00:00
|
|
|
if len(new_notes) > config.world.character.note_limit:
|
2024-05-27 01:07:03 +00:00
|
|
|
raise ActionError(
|
2024-05-31 23:58:01 +00:00
|
|
|
format_prompt(
|
|
|
|
"action_summarize_notes_error_limit",
|
2024-06-01 19:46:11 +00:00
|
|
|
limit=config.world.character.note_limit,
|
2024-05-31 23:58:01 +00:00
|
|
|
)
|
2024-05-27 01:07:03 +00:00
|
|
|
)
|
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
action_character.planner.notes[:] = new_notes
|
2024-05-31 23:58:01 +00:00
|
|
|
return get_prompt("action_summarize_notes_result")
|
2024-05-27 01:07:03 +00:00
|
|
|
|
|
|
|
|
2024-05-25 20:18:40 +00:00
|
|
|
def schedule_event(name: str, turns: int):
|
|
|
|
"""
|
|
|
|
Schedule an event to happen at a specific turn. Events are important occurrences that can affect the world in
|
2024-05-26 20:59:12 +00:00
|
|
|
significant ways. You will be notified about upcoming events so you can plan accordingly. Make sure you inform
|
|
|
|
other characters about events that involve them, and give them enough time to prepare.
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
Args:
|
|
|
|
name: The name of the event.
|
|
|
|
turns: The number of turns until the event happens.
|
|
|
|
"""
|
|
|
|
|
2024-06-05 03:07:26 +00:00
|
|
|
config = get_game_config()
|
2024-06-01 09:51:47 +00:00
|
|
|
current_turn = get_current_turn()
|
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
with action_context() as (_, action_character):
|
2024-05-31 23:58:01 +00:00
|
|
|
if not name:
|
|
|
|
raise ActionError(get_prompt("action_schedule_event_error_name"))
|
|
|
|
|
2024-06-05 03:07:26 +00:00
|
|
|
if (
|
|
|
|
len(action_character.planner.calendar.events)
|
|
|
|
>= config.world.character.event_limit
|
|
|
|
):
|
|
|
|
raise ActionError(get_prompt("action_schedule_event_error_limit"))
|
|
|
|
|
|
|
|
if name in [event.name for event in action_character.planner.calendar.events]:
|
|
|
|
raise ActionError(get_prompt("action_schedule_event_error_duplicate"))
|
|
|
|
|
2024-06-01 09:51:47 +00:00
|
|
|
event = CalendarEvent(name, turns + current_turn)
|
2024-05-27 01:32:03 +00:00
|
|
|
action_character.planner.calendar.events.append(event)
|
2024-05-31 23:58:01 +00:00
|
|
|
return format_prompt("action_schedule_event_result", name=name, turns=turns)
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
|
2024-05-27 02:33:44 +00:00
|
|
|
def check_calendar(count: int):
|
2024-05-25 20:18:40 +00:00
|
|
|
"""
|
|
|
|
Read your calendar to see upcoming events that you have scheduled.
|
2024-05-27 02:33:44 +00:00
|
|
|
|
|
|
|
Args:
|
|
|
|
count: The number of upcoming events to read. 5 is usually a good number.
|
2024-05-25 20:18:40 +00:00
|
|
|
"""
|
|
|
|
|
2024-06-01 19:46:11 +00:00
|
|
|
config = get_game_config()
|
|
|
|
|
|
|
|
count = min(count, config.world.character.event_limit)
|
2024-05-27 12:54:36 +00:00
|
|
|
current_turn = get_current_turn()
|
2024-05-25 20:18:40 +00:00
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
with action_context() as (_, action_character):
|
2024-05-27 02:33:44 +00:00
|
|
|
if len(action_character.planner.calendar.events) == 0:
|
2024-05-31 23:58:01 +00:00
|
|
|
return get_prompt("action_check_calendar_empty")
|
2024-05-27 02:33:44 +00:00
|
|
|
|
2024-05-27 01:32:03 +00:00
|
|
|
events = action_character.planner.calendar.events[:count]
|
2024-05-25 20:18:40 +00:00
|
|
|
return "\n".join(
|
|
|
|
[
|
2024-05-31 23:58:01 +00:00
|
|
|
format_prompt(
|
|
|
|
"action_check_calendar_each",
|
|
|
|
name=event.name,
|
2024-06-01 09:51:47 +00:00
|
|
|
turns=event.turn - current_turn,
|
2024-05-31 23:58:01 +00:00
|
|
|
)
|
2024-05-25 20:18:40 +00:00
|
|
|
for event in events
|
|
|
|
]
|
|
|
|
)
|
2024-06-16 22:52:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
def init():
|
|
|
|
return add_extra_actions(
|
|
|
|
PLANNING_SYSTEM_NAME,
|
|
|
|
[
|
|
|
|
take_note,
|
|
|
|
read_notes,
|
|
|
|
erase_notes,
|
|
|
|
edit_note,
|
|
|
|
summarize_notes,
|
|
|
|
schedule_event,
|
|
|
|
check_calendar,
|
|
|
|
],
|
|
|
|
)
|