2024-05-09 02:11:16 +00:00
|
|
|
import atexit
|
2024-05-27 03:42:08 +00:00
|
|
|
from functools import partial
|
2024-06-05 02:15:36 +00:00
|
|
|
from glob import glob
|
2024-05-04 20:35:42 +00:00
|
|
|
from logging.config import dictConfig
|
2024-05-03 01:57:11 +00:00
|
|
|
from os import environ, path
|
2024-05-09 02:11:16 +00:00
|
|
|
from typing import List
|
2024-05-02 11:25:35 +00:00
|
|
|
|
2024-05-03 01:57:11 +00:00
|
|
|
from dotenv import load_dotenv
|
2024-05-02 11:25:35 +00:00
|
|
|
from packit.agent import Agent, agent_easy_connect
|
2024-05-27 03:42:08 +00:00
|
|
|
from packit.memory import make_limited_memory
|
2024-05-02 11:25:35 +00:00
|
|
|
from packit.utils import logger_with_colors
|
2024-05-09 02:11:16 +00:00
|
|
|
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.utils.file import load_yaml
|
2024-05-09 02:11:16 +00:00
|
|
|
|
|
|
|
# configure logging
|
2024-05-04 20:35:42 +00:00
|
|
|
LOG_PATH = "logging.json"
|
|
|
|
try:
|
|
|
|
if path.exists(LOG_PATH):
|
|
|
|
with open(LOG_PATH, "r") as f:
|
2024-05-09 02:11:16 +00:00
|
|
|
config_logging = load_yaml(f)
|
2024-05-04 20:35:42 +00:00
|
|
|
dictConfig(config_logging)
|
|
|
|
else:
|
|
|
|
print("logging config not found")
|
|
|
|
|
|
|
|
except Exception as err:
|
|
|
|
print("error loading logging config: %s" % (err))
|
|
|
|
|
|
|
|
|
2024-05-12 20:47:18 +00:00
|
|
|
logger = logger_with_colors(__name__) # , level="DEBUG")
|
2024-05-02 11:25:35 +00:00
|
|
|
|
2024-06-01 19:46:11 +00:00
|
|
|
load_dotenv(environ.get("TALEWEAVE_ENV", ".env"), override=True)
|
2024-05-03 01:57:11 +00:00
|
|
|
|
2024-05-18 21:20:47 +00:00
|
|
|
if True:
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.context import (
|
2024-05-31 23:58:01 +00:00
|
|
|
get_prompt_library,
|
2024-05-27 03:27:13 +00:00
|
|
|
get_system_data,
|
2024-05-27 12:54:36 +00:00
|
|
|
set_current_turn,
|
2024-05-27 03:27:13 +00:00
|
|
|
set_dungeon_master,
|
2024-06-01 19:46:11 +00:00
|
|
|
set_game_config,
|
2024-05-27 03:27:13 +00:00
|
|
|
set_system_data,
|
|
|
|
subscribe,
|
|
|
|
)
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.game_system import GameSystem
|
|
|
|
from taleweave.generate import generate_room, generate_world, link_rooms
|
|
|
|
from taleweave.models.config import DEFAULT_CONFIG, Config
|
|
|
|
from taleweave.models.entity import World, WorldState
|
|
|
|
from taleweave.models.event import GenerateEvent
|
2024-06-05 03:07:26 +00:00
|
|
|
from taleweave.models.files import TemplateFile, WorldPrompt
|
2024-05-31 23:58:01 +00:00
|
|
|
from taleweave.models.prompt import PromptLibrary
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.plugins import load_plugin
|
|
|
|
from taleweave.simulate import simulate_world
|
2024-06-03 01:14:41 +00:00
|
|
|
from taleweave.state import create_agents, save_world, save_world_state
|
2024-05-31 23:58:01 +00:00
|
|
|
from taleweave.utils.prompt import format_prompt
|
2024-05-02 11:25:35 +00:00
|
|
|
|
2024-05-10 04:45:10 +00:00
|
|
|
# start the debugger, if needed
|
|
|
|
if environ.get("DEBUG", "false").lower() == "true":
|
|
|
|
import debugpy
|
|
|
|
|
|
|
|
debugpy.listen(5679)
|
|
|
|
logger.info("waiting for debugger to attach...")
|
|
|
|
debugpy.wait_for_client()
|
|
|
|
|
|
|
|
|
2024-05-18 21:20:47 +00:00
|
|
|
def int_or_inf(value: str) -> float | int:
|
|
|
|
if value == "inf":
|
|
|
|
return float("inf")
|
|
|
|
|
|
|
|
return int(value)
|
|
|
|
|
|
|
|
|
2024-05-02 11:25:35 +00:00
|
|
|
# main
|
|
|
|
def parse_args():
|
|
|
|
import argparse
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(
|
2024-05-04 04:18:21 +00:00
|
|
|
description="Generate and simulate a text adventure world"
|
2024-05-02 11:25:35 +00:00
|
|
|
)
|
2024-05-02 14:20:47 +00:00
|
|
|
parser.add_argument(
|
2024-05-04 04:18:21 +00:00
|
|
|
"--actions",
|
|
|
|
type=str,
|
|
|
|
nargs="*",
|
|
|
|
help="Extra actions to include in the simulation",
|
2024-05-02 14:20:47 +00:00
|
|
|
)
|
2024-05-27 03:27:13 +00:00
|
|
|
parser.add_argument(
|
|
|
|
"--add-rooms",
|
|
|
|
default=0,
|
|
|
|
type=int,
|
|
|
|
help="The number of new rooms to generate before starting the simulation",
|
|
|
|
)
|
2024-05-02 23:17:13 +00:00
|
|
|
parser.add_argument(
|
2024-05-12 20:47:18 +00:00
|
|
|
"--config",
|
|
|
|
type=str,
|
2024-05-18 21:20:47 +00:00
|
|
|
help="The file to load additional configuration from",
|
2024-05-12 20:47:18 +00:00
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--discord",
|
|
|
|
action="store_true",
|
|
|
|
help="Whether to run the simulation in a Discord bot",
|
2024-05-08 01:40:53 +00:00
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--flavor",
|
|
|
|
type=str,
|
|
|
|
default="",
|
|
|
|
help="Some additional flavor text for the generated world",
|
2024-05-02 23:17:13 +00:00
|
|
|
)
|
2024-05-12 20:47:18 +00:00
|
|
|
parser.add_argument(
|
|
|
|
"--optional-actions",
|
|
|
|
action="store_true",
|
2024-05-18 21:20:47 +00:00
|
|
|
help="Whether to include optional actions in the simulation",
|
2024-05-12 20:47:18 +00:00
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--player",
|
|
|
|
type=str,
|
|
|
|
help="The name of the character to play as",
|
2024-05-02 23:17:13 +00:00
|
|
|
)
|
2024-05-31 23:58:01 +00:00
|
|
|
parser.add_argument(
|
|
|
|
"--prompts",
|
|
|
|
type=str,
|
|
|
|
nargs="*",
|
|
|
|
help="The file to load game prompts from",
|
|
|
|
)
|
2024-05-03 01:57:11 +00:00
|
|
|
parser.add_argument(
|
2024-05-12 20:47:18 +00:00
|
|
|
"--render",
|
|
|
|
action="store_true",
|
2024-05-18 21:20:47 +00:00
|
|
|
help="Whether to run the render thread",
|
2024-05-03 01:57:11 +00:00
|
|
|
)
|
|
|
|
parser.add_argument(
|
2024-05-12 20:47:18 +00:00
|
|
|
"--render-generated",
|
|
|
|
action="store_true",
|
|
|
|
help="Whether to render entities as they are generated",
|
2024-05-03 01:57:11 +00:00
|
|
|
)
|
2024-05-04 22:57:24 +00:00
|
|
|
parser.add_argument(
|
2024-05-12 20:47:18 +00:00
|
|
|
"--rooms",
|
|
|
|
type=int,
|
|
|
|
help="The number of rooms to generate",
|
2024-05-04 22:57:24 +00:00
|
|
|
)
|
2024-05-04 04:18:21 +00:00
|
|
|
parser.add_argument(
|
2024-05-12 20:47:18 +00:00
|
|
|
"--server",
|
2024-05-16 04:12:06 +00:00
|
|
|
action="store_true",
|
2024-05-18 21:20:47 +00:00
|
|
|
help="Whether to run the websocket server",
|
2024-05-04 04:18:21 +00:00
|
|
|
)
|
2024-05-02 23:17:13 +00:00
|
|
|
parser.add_argument(
|
|
|
|
"--state",
|
|
|
|
type=str,
|
|
|
|
help="The file to save the world state to. Defaults to $world.state.json, if not set",
|
|
|
|
)
|
2024-05-02 11:25:35 +00:00
|
|
|
parser.add_argument(
|
2024-05-27 12:54:36 +00:00
|
|
|
"--turns",
|
2024-05-18 21:20:47 +00:00
|
|
|
type=int_or_inf,
|
2024-05-12 20:47:18 +00:00
|
|
|
default=10,
|
2024-05-27 12:54:36 +00:00
|
|
|
help="The number of simulation turns to run",
|
2024-05-02 11:25:35 +00:00
|
|
|
)
|
2024-05-04 04:18:21 +00:00
|
|
|
parser.add_argument(
|
|
|
|
"--systems",
|
|
|
|
type=str,
|
|
|
|
nargs="*",
|
2024-05-05 14:14:54 +00:00
|
|
|
help="Extra systems to run in the simulation",
|
2024-05-04 04:18:21 +00:00
|
|
|
)
|
2024-05-02 11:25:35 +00:00
|
|
|
parser.add_argument(
|
2024-05-12 20:47:18 +00:00
|
|
|
"--theme",
|
|
|
|
type=str,
|
|
|
|
default="fantasy",
|
|
|
|
help="The theme of the generated world",
|
2024-05-02 11:25:35 +00:00
|
|
|
)
|
|
|
|
parser.add_argument(
|
|
|
|
"--world",
|
|
|
|
type=str,
|
2024-05-02 14:20:47 +00:00
|
|
|
default="world",
|
2024-05-02 11:25:35 +00:00
|
|
|
help="The file to save the generated world to",
|
|
|
|
)
|
2024-05-09 02:11:16 +00:00
|
|
|
parser.add_argument(
|
2024-05-12 20:47:18 +00:00
|
|
|
"--world-template",
|
2024-05-09 02:11:16 +00:00
|
|
|
type=str,
|
2024-05-12 20:47:18 +00:00
|
|
|
help="The template file to load the world prompt from",
|
2024-05-09 02:11:16 +00:00
|
|
|
)
|
2024-05-02 11:25:35 +00:00
|
|
|
return parser.parse_args()
|
|
|
|
|
|
|
|
|
2024-05-09 02:11:16 +00:00
|
|
|
def get_world_prompt(args) -> WorldPrompt:
|
2024-05-12 20:47:18 +00:00
|
|
|
if args.world_template:
|
|
|
|
prompt_file, prompt_name = args.world_template.split(":")
|
2024-05-09 02:11:16 +00:00
|
|
|
with open(prompt_file, "r") as f:
|
2024-06-05 03:07:26 +00:00
|
|
|
prompts = TemplateFile(**load_yaml(f))
|
|
|
|
for prompt in prompts.templates:
|
2024-05-09 02:11:16 +00:00
|
|
|
if prompt.name == prompt_name:
|
|
|
|
return prompt
|
2024-05-02 11:25:35 +00:00
|
|
|
|
2024-05-09 02:11:16 +00:00
|
|
|
logger.warning(f"prompt {prompt_name} not found in {prompt_file}")
|
2024-05-02 14:20:47 +00:00
|
|
|
|
2024-05-09 02:11:16 +00:00
|
|
|
return WorldPrompt(
|
|
|
|
name=args.world,
|
|
|
|
theme=args.theme,
|
|
|
|
flavor=args.flavor,
|
|
|
|
)
|
2024-05-08 01:42:10 +00:00
|
|
|
|
2024-05-04 20:35:42 +00:00
|
|
|
|
2024-05-31 23:58:01 +00:00
|
|
|
def load_prompt_library(args) -> None:
|
|
|
|
if args.prompts:
|
2024-06-05 02:15:36 +00:00
|
|
|
prompt_files = []
|
2024-05-31 23:58:01 +00:00
|
|
|
for prompt_file in args.prompts:
|
2024-06-05 02:15:36 +00:00
|
|
|
prompt_files.extend(glob(prompt_file, recursive=True))
|
|
|
|
|
|
|
|
for prompt_file in prompt_files:
|
2024-05-31 23:58:01 +00:00
|
|
|
with open(prompt_file, "r") as f:
|
|
|
|
new_library = PromptLibrary(**load_yaml(f))
|
2024-06-04 13:59:50 +00:00
|
|
|
logger.info(f"loaded prompt library from {prompt_file}")
|
2024-05-31 23:58:01 +00:00
|
|
|
library = get_prompt_library()
|
|
|
|
library.prompts.update(new_library.prompts)
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2024-05-25 20:18:40 +00:00
|
|
|
def load_or_initialize_system_data(args, systems: List[GameSystem], world: World):
|
|
|
|
for system in systems:
|
|
|
|
if system.data:
|
|
|
|
system_data_file = f"{args.world}.{system.name}.json"
|
|
|
|
|
|
|
|
if path.exists(system_data_file):
|
|
|
|
logger.info(f"loading system data from {system_data_file}")
|
|
|
|
data = system.data.load(system_data_file)
|
2024-05-26 20:59:12 +00:00
|
|
|
set_system_data(system.name, data)
|
2024-05-29 00:55:32 +00:00
|
|
|
continue
|
2024-05-25 20:18:40 +00:00
|
|
|
else:
|
|
|
|
logger.info(f"no system data found at {system_data_file}")
|
2024-05-29 00:55:32 +00:00
|
|
|
|
|
|
|
if system.initialize:
|
|
|
|
logger.info(f"initializing system data for {system.name}")
|
|
|
|
data = system.initialize(world)
|
|
|
|
set_system_data(system.name, data)
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
def save_system_data(args, systems: List[GameSystem]):
|
|
|
|
for system in systems:
|
|
|
|
if system.data:
|
|
|
|
system_data_file = f"{args.world}.{system.name}.json"
|
|
|
|
logger.info(f"saving system data to {system_data_file}")
|
|
|
|
system.data.save(system_data_file, get_system_data(system.name))
|
|
|
|
|
|
|
|
|
|
|
|
def load_or_generate_world(
|
2024-06-03 01:14:41 +00:00
|
|
|
args, config: Config, players, systems: List[GameSystem], world_prompt: WorldPrompt
|
2024-05-25 20:18:40 +00:00
|
|
|
):
|
2024-05-09 02:11:16 +00:00
|
|
|
world_file = args.world + ".json"
|
|
|
|
world_state_file = args.state or (args.world + ".state.json")
|
2024-05-27 03:27:13 +00:00
|
|
|
add_rooms = args.add_rooms
|
2024-05-04 20:35:42 +00:00
|
|
|
|
2024-05-02 23:17:13 +00:00
|
|
|
memory = {}
|
2024-05-27 12:54:36 +00:00
|
|
|
turn = 0
|
2024-05-26 21:18:48 +00:00
|
|
|
|
2024-05-27 03:27:13 +00:00
|
|
|
# prepare an agent for the world builder
|
|
|
|
llm = agent_easy_connect()
|
2024-06-03 01:14:41 +00:00
|
|
|
memory_factory = partial(
|
|
|
|
make_limited_memory, limit=config.world.character.memory_limit
|
|
|
|
)
|
2024-05-27 03:27:13 +00:00
|
|
|
world_builder = Agent(
|
|
|
|
"World Builder",
|
2024-05-31 23:58:01 +00:00
|
|
|
format_prompt(
|
|
|
|
"world_generate_dungeon_master",
|
|
|
|
flavor=world_prompt.flavor,
|
|
|
|
theme=world_prompt.theme,
|
|
|
|
),
|
2024-05-27 03:27:13 +00:00
|
|
|
{},
|
|
|
|
llm,
|
2024-05-27 03:42:08 +00:00
|
|
|
memory_factory=memory_factory,
|
2024-05-27 03:27:13 +00:00
|
|
|
)
|
2024-06-05 02:15:36 +00:00
|
|
|
set_dungeon_master(world_builder)
|
2024-05-27 03:27:13 +00:00
|
|
|
|
2024-05-02 14:20:47 +00:00
|
|
|
if path.exists(world_state_file):
|
2024-05-09 02:11:16 +00:00
|
|
|
logger.info(f"loading world state from {world_state_file}")
|
2024-05-02 14:20:47 +00:00
|
|
|
with open(world_state_file, "r") as f:
|
2024-05-09 02:11:16 +00:00
|
|
|
state = WorldState(**load_yaml(f))
|
2024-05-02 11:25:35 +00:00
|
|
|
|
2024-05-27 12:54:36 +00:00
|
|
|
set_current_turn(state.turn)
|
2024-05-25 20:18:40 +00:00
|
|
|
load_or_initialize_system_data(args, systems, state.world)
|
2024-05-02 14:20:47 +00:00
|
|
|
|
2024-05-02 23:17:13 +00:00
|
|
|
memory = state.memory
|
2024-05-27 12:54:36 +00:00
|
|
|
turn = state.turn
|
2024-05-02 11:25:35 +00:00
|
|
|
world = state.world
|
2024-05-02 14:20:47 +00:00
|
|
|
elif path.exists(world_file):
|
2024-05-09 02:11:16 +00:00
|
|
|
logger.info(f"loading world from {world_file}")
|
2024-05-02 14:20:47 +00:00
|
|
|
with open(world_file, "r") as f:
|
2024-05-09 02:11:16 +00:00
|
|
|
world = World(**load_yaml(f))
|
2024-05-25 20:18:40 +00:00
|
|
|
|
|
|
|
load_or_initialize_system_data(args, systems, world)
|
2024-05-02 11:25:35 +00:00
|
|
|
else:
|
2024-05-09 02:11:16 +00:00
|
|
|
logger.info(f"generating a new world using theme: {world_prompt.theme}")
|
2024-05-03 01:57:11 +00:00
|
|
|
world = generate_world(
|
2024-05-08 01:40:53 +00:00
|
|
|
world_builder,
|
2024-05-04 04:18:21 +00:00
|
|
|
args.world,
|
2024-05-09 02:11:16 +00:00
|
|
|
world_prompt.theme,
|
2024-05-19 04:30:17 +00:00
|
|
|
systems,
|
2024-05-04 04:18:21 +00:00
|
|
|
room_count=args.rooms,
|
2024-05-03 01:57:11 +00:00
|
|
|
)
|
2024-06-05 02:15:36 +00:00
|
|
|
load_or_initialize_system_data(args, systems, world)
|
|
|
|
|
2024-05-02 14:20:47 +00:00
|
|
|
save_world(world, world_file)
|
2024-05-25 20:18:40 +00:00
|
|
|
save_system_data(args, systems)
|
2024-05-12 20:47:18 +00:00
|
|
|
|
2024-05-27 03:27:13 +00:00
|
|
|
new_rooms = []
|
|
|
|
for i in range(add_rooms):
|
|
|
|
logger.info(f"generating room {i + 1} of {add_rooms}")
|
2024-06-05 13:58:35 +00:00
|
|
|
room = generate_room(
|
|
|
|
world_builder, world, systems, current_room=i, total_rooms=add_rooms
|
|
|
|
)
|
2024-05-27 03:27:13 +00:00
|
|
|
new_rooms.append(room)
|
|
|
|
world.rooms.append(room)
|
|
|
|
|
|
|
|
if new_rooms:
|
|
|
|
link_rooms(world_builder, world, systems, new_rooms)
|
|
|
|
|
2024-05-02 23:17:13 +00:00
|
|
|
create_agents(world, memory=memory, players=players)
|
2024-05-27 12:54:36 +00:00
|
|
|
return (world, world_state_file, turn)
|
2024-05-09 02:11:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
args = parse_args()
|
|
|
|
|
2024-05-18 21:20:47 +00:00
|
|
|
if args.config:
|
|
|
|
with open(args.config, "r") as f:
|
|
|
|
config = Config(**load_yaml(f))
|
2024-06-01 19:46:11 +00:00
|
|
|
set_game_config(config)
|
2024-05-18 21:20:47 +00:00
|
|
|
else:
|
|
|
|
config = DEFAULT_CONFIG
|
2024-05-12 20:47:18 +00:00
|
|
|
|
2024-05-31 23:58:01 +00:00
|
|
|
load_prompt_library(args)
|
|
|
|
|
2024-05-09 02:11:16 +00:00
|
|
|
players = []
|
|
|
|
if args.player:
|
|
|
|
players.append(args.player)
|
|
|
|
|
|
|
|
# launch other threads
|
|
|
|
threads = []
|
2024-05-12 05:08:53 +00:00
|
|
|
|
|
|
|
if args.render:
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.render.comfy import launch_render, render_generated
|
2024-05-12 05:08:53 +00:00
|
|
|
|
2024-05-12 20:47:18 +00:00
|
|
|
threads.extend(launch_render(config.render))
|
|
|
|
if args.render_generated:
|
2024-05-18 21:58:11 +00:00
|
|
|
subscribe(GenerateEvent, render_generated)
|
2024-05-12 05:08:53 +00:00
|
|
|
|
2024-05-09 02:11:16 +00:00
|
|
|
if args.discord:
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.bot.discord import launch_bot
|
2024-05-09 02:11:16 +00:00
|
|
|
|
2024-05-12 20:47:18 +00:00
|
|
|
threads.extend(launch_bot(config.bot.discord))
|
2024-05-09 02:11:16 +00:00
|
|
|
|
2024-05-04 22:17:56 +00:00
|
|
|
if args.server:
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.server.websocket import launch_server
|
2024-05-02 23:17:13 +00:00
|
|
|
|
2024-05-18 21:58:11 +00:00
|
|
|
threads.extend(launch_server(config.server.websocket))
|
2024-05-02 11:25:35 +00:00
|
|
|
|
2024-05-09 02:11:16 +00:00
|
|
|
# register the thread shutdown handler
|
|
|
|
def shutdown_threads():
|
|
|
|
for thread in threads:
|
|
|
|
thread.join(1.0)
|
|
|
|
|
|
|
|
atexit.register(shutdown_threads)
|
|
|
|
|
|
|
|
# load built-in but optional actions
|
|
|
|
extra_actions = []
|
2024-05-04 22:57:24 +00:00
|
|
|
if args.optional_actions:
|
2024-05-09 02:11:16 +00:00
|
|
|
logger.info("loading optional actions")
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.actions.optional import init as init_optional_actions
|
2024-05-04 22:57:24 +00:00
|
|
|
|
|
|
|
optional_actions = init_optional_actions()
|
|
|
|
logger.info(
|
2024-05-09 02:11:16 +00:00
|
|
|
f"loaded optional actions: {[action.__name__ for action in optional_actions]}"
|
2024-05-04 22:57:24 +00:00
|
|
|
)
|
|
|
|
extra_actions.extend(optional_actions)
|
|
|
|
|
2024-05-09 02:11:16 +00:00
|
|
|
# load extra actions from plugins
|
|
|
|
for action_name in args.actions or []:
|
|
|
|
logger.info(f"loading extra actions from {action_name}")
|
|
|
|
module_actions = load_plugin(action_name)
|
|
|
|
logger.info(
|
|
|
|
f"loaded extra actions: {[action.__name__ for action in module_actions]}"
|
|
|
|
)
|
|
|
|
extra_actions.extend(module_actions)
|
2024-05-04 04:18:21 +00:00
|
|
|
|
2024-05-09 02:11:16 +00:00
|
|
|
# load extra systems from plugins
|
2024-05-16 04:12:06 +00:00
|
|
|
extra_systems: List[GameSystem] = []
|
2024-05-04 22:17:56 +00:00
|
|
|
for system_name in args.systems or []:
|
2024-05-09 02:11:16 +00:00
|
|
|
logger.info(f"loading extra systems from {system_name}")
|
2024-05-04 04:18:21 +00:00
|
|
|
module_systems = load_plugin(system_name)
|
2024-05-16 04:12:06 +00:00
|
|
|
logger.info(f"loaded extra systems: {module_systems}")
|
2024-05-08 01:40:53 +00:00
|
|
|
extra_systems.extend(module_systems)
|
2024-05-04 04:18:21 +00:00
|
|
|
|
2024-05-04 20:35:42 +00:00
|
|
|
# make sure the server system runs after any updates
|
2024-05-04 04:18:21 +00:00
|
|
|
if args.server:
|
2024-05-27 13:10:24 +00:00
|
|
|
from taleweave.server.websocket import server_system
|
2024-05-18 22:29:40 +00:00
|
|
|
|
2024-05-25 20:18:40 +00:00
|
|
|
extra_systems.append(GameSystem(name="server", simulate=server_system))
|
2024-05-04 04:18:21 +00:00
|
|
|
|
2024-05-09 02:11:16 +00:00
|
|
|
# load or generate the world
|
|
|
|
world_prompt = get_world_prompt(args)
|
2024-05-27 12:54:36 +00:00
|
|
|
world, world_state_file, world_turn = load_or_generate_world(
|
2024-06-03 01:14:41 +00:00
|
|
|
args, config, players, extra_systems, world_prompt=world_prompt
|
2024-05-09 02:11:16 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
# make sure the snapshot system runs last
|
2024-05-27 12:54:36 +00:00
|
|
|
def snapshot_system(world: World, turn: int, data: None = None) -> None:
|
2024-05-09 02:11:16 +00:00
|
|
|
logger.info("taking snapshot of world state")
|
2024-05-27 12:54:36 +00:00
|
|
|
save_world_state(world, turn, world_state_file)
|
2024-05-09 02:11:16 +00:00
|
|
|
|
2024-05-25 20:18:40 +00:00
|
|
|
extra_systems.append(GameSystem(name="snapshot", simulate=snapshot_system))
|
2024-05-09 02:11:16 +00:00
|
|
|
|
2024-05-12 20:47:18 +00:00
|
|
|
# hack: send a snapshot to the websocket server
|
|
|
|
if args.server:
|
2024-05-27 12:54:36 +00:00
|
|
|
server_system(world, world_turn)
|
2024-05-09 02:11:16 +00:00
|
|
|
|
2024-05-08 01:40:53 +00:00
|
|
|
# create the DM
|
|
|
|
llm = agent_easy_connect()
|
2024-06-03 01:14:41 +00:00
|
|
|
memory_factory = partial(
|
|
|
|
make_limited_memory, limit=config.world.character.memory_limit
|
|
|
|
)
|
2024-05-08 01:40:53 +00:00
|
|
|
world_builder = Agent(
|
|
|
|
"dungeon master",
|
2024-05-31 23:58:01 +00:00
|
|
|
format_prompt(
|
|
|
|
"world_generate_dungeon_master", flavor=args.flavor, theme=world.theme
|
2024-05-08 01:40:53 +00:00
|
|
|
),
|
|
|
|
{},
|
|
|
|
llm,
|
2024-05-27 03:42:08 +00:00
|
|
|
memory_factory=memory_factory,
|
2024-05-08 01:40:53 +00:00
|
|
|
)
|
|
|
|
set_dungeon_master(world_builder)
|
|
|
|
|
2024-05-04 04:18:21 +00:00
|
|
|
# start the sim
|
2024-06-03 01:00:17 +00:00
|
|
|
logger.debug("simulating world: %s", world.name)
|
2024-05-02 11:56:57 +00:00
|
|
|
simulate_world(
|
|
|
|
world,
|
2024-05-27 12:54:36 +00:00
|
|
|
turns=args.turns,
|
2024-05-04 04:18:21 +00:00
|
|
|
actions=extra_actions,
|
|
|
|
systems=extra_systems,
|
2024-05-02 11:56:57 +00:00
|
|
|
)
|
2024-05-02 11:25:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|