mirror of
https://github.com/vegu-ai/talemate.git
synced 2025-12-28 16:06:38 +01:00
0.22.0 (#89)
* linux dev instance shortcuts * add voice samples to gitignore * direction mode: inner monologue * actor direction fixes * py script support for scene logic * fix end_simulation call * port sim suite logic to python * remove dupe log * fix typing * section off the text * fix end simulation command * simulation goal, prompt tweaks * prompt tweaks * dialogue format improvements * director action logged with message * call director action log and other fixes * generate character dialogue instructions, prompt fixes, director action ux * fix question / answer call * generate dialogue instructions when loading from character cards * more dialogue format improvements * set scene content context more reliably. * fix innermonologue perspective * conversation prompt should honor the client's decensor setting * fix comfyui checkpoint list not loading * more dialogue format fixes * prompt tweaks * fix sim suite group characters, prompt fixes * npm relock * handle inanimate objects, handle player name change issues * don't rename details if the original name was "You" * As the conversation goes on, dialogue instructions should be moved backwards further to have a weaker effect on immediate generations. * add more context to character creation prompt * fix select next talking actor when natural language flow is turned on and the LLM returns multiple character names * prompt fixes for dialogue generation * summarization fixes * default to script format * seperate dialogue prompt by formatting style, tweak conversation system prompt * remove cruft * add gen format to agent details * relock * relock * prep 0.22.0 * add claude-3-haiku-20240307 * readme
This commit is contained in:
469
scenes/simulation-suite/game.py
Normal file
469
scenes/simulation-suite/game.py
Normal file
@@ -0,0 +1,469 @@
|
||||
|
||||
def game(TM):
|
||||
|
||||
MSG_PROCESSED_INSTRUCTIONS = "Simulation suite processed instructions"
|
||||
|
||||
MSG_HELP = "Instructions to the simulation computer are only process if the computer is addressed at the beginning of the instruction. Please state your commands by addressing the computer by stating \"Computer,\" followed by an instruction. For example ... \"Computer, i want to experience being on a derelict spaceship.\""
|
||||
|
||||
PROMPT_NARRATE_ROUND = "Narrate the simulation and reveal some new details to the player in one paragraph. YOU MUST NOT ADDRESS THE COMPUTER OR THE SIMULATION."
|
||||
|
||||
PROMPT_STARTUP = "Narrate the computer asking the user to state the nature of their desired simulation."
|
||||
|
||||
CTX_PIN_UNAWARE = "Characters in the simulation ARE NOT AWARE OF THE COMPUTER."
|
||||
|
||||
def parse_sim_call_arguments(call:str) -> str:
|
||||
"""
|
||||
Returns the value between the parentheses of a simulation call
|
||||
|
||||
Example:
|
||||
|
||||
call = 'change_environment("a house")'
|
||||
|
||||
parse_sim_call_arguments(call) -> "a house"
|
||||
"""
|
||||
|
||||
try:
|
||||
return call.split("(", 1)[1].split(")")[0]
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
class SimulationSuite:
|
||||
|
||||
def __init__(self):
|
||||
# do we update the world state at the end of the round
|
||||
self.update_world_state = False
|
||||
|
||||
self.simulation_reset = False
|
||||
|
||||
self.added_npcs = []
|
||||
|
||||
TM.log.debug("SIMULATION SUITE INIT...")
|
||||
|
||||
self.player_character = TM.scene.get_player_character()
|
||||
self.player_message = TM.scene.last_player_message()
|
||||
self.last_processed_call = TM.game_state.get_var("instr.lastprocessed_call", -1)
|
||||
self.player_message_is_instruction = (
|
||||
self.player_message and
|
||||
self.player_message.raw.lower().startswith("computer") and
|
||||
not self.player_message.hidden and
|
||||
not self.last_processed_call > self.player_message.id
|
||||
)
|
||||
|
||||
|
||||
def run(self):
|
||||
if not TM.game_state.has_var("instr.simulation_stopped"):
|
||||
self.simulation()
|
||||
|
||||
self.finalize_round()
|
||||
|
||||
def simulation(self):
|
||||
|
||||
if not TM.game_state.has_var("instr.simulation_started"):
|
||||
self.startup()
|
||||
else:
|
||||
self.simulation_calls()
|
||||
|
||||
if self.update_world_state:
|
||||
self.run_update_world_state(force=True)
|
||||
|
||||
|
||||
def startup(self):
|
||||
TM.emit_status("busy", "Simulation suite powering up.", as_scene_message=True)
|
||||
TM.game_state.set_var("instr.simulation_started", "yes", commit=False)
|
||||
TM.agents.narrator.action_to_narration(
|
||||
action_name="progress_story",
|
||||
narrative_direction=PROMPT_STARTUP,
|
||||
emit_message=False
|
||||
)
|
||||
TM.agents.narrator.action_to_narration(
|
||||
action_name="passthrough",
|
||||
narration=MSG_HELP
|
||||
)
|
||||
TM.agents.world_state.manager(
|
||||
action_name="save_world_entry",
|
||||
entry_id="sim.quarantined",
|
||||
text=CTX_PIN_UNAWARE,
|
||||
meta={},
|
||||
pin=True
|
||||
)
|
||||
TM.game_state.set_var("instr.simulation_started", "yes", commit=False)
|
||||
TM.emit_status("success", "Simulation suite ready", as_scene_message=True)
|
||||
self.update_world_state = True
|
||||
|
||||
def simulation_calls(self):
|
||||
"""
|
||||
Calls the simulation suite main prompt to determine the appropriate
|
||||
simulation calls
|
||||
"""
|
||||
|
||||
if not self.player_message_is_instruction or self.player_message.id == self.last_processed_call:
|
||||
return
|
||||
|
||||
# First instruction?
|
||||
if not TM.game_state.has_var("instr.has_issued_instructions"):
|
||||
|
||||
# determine the context of the simulation
|
||||
|
||||
context_context = TM.agents.creator.determine_content_context_for_description(
|
||||
description=self.player_message.raw,
|
||||
)
|
||||
TM.scene.set_content_context(context_context)
|
||||
|
||||
|
||||
calls = TM.client.render_and_request(
|
||||
"computer",
|
||||
dedupe_enabled=False,
|
||||
player_instruction=self.player_message.raw,
|
||||
scene=TM.scene,
|
||||
)
|
||||
|
||||
calls = calls.split("\n")
|
||||
|
||||
calls = self.prepare_calls(calls)
|
||||
|
||||
TM.log.debug("SIMULATION SUITE CALLS", callse=calls)
|
||||
|
||||
# calls that are processed
|
||||
processed = []
|
||||
|
||||
for call in calls:
|
||||
processed_call = self.process_call(call)
|
||||
if processed_call:
|
||||
processed.append(processed_call)
|
||||
|
||||
"""
|
||||
{% set _ = emit_status("busy", "Simulation suite altering environment.", as_scene_message=True) %}
|
||||
{% set update_world_state = True %}
|
||||
{% set _ = agent_action("narrator", "action_to_narration", action_name="progress_story", narrative_direction="The computer calls the following functions:\n"+processed.join("\n")+"\nand the simulation adjusts the environment according to the user's wishes.\n\nWrite the narrative that describes the changes to the player in the context of the simulation starting up.", emit_message=True) %}
|
||||
"""
|
||||
|
||||
if processed:
|
||||
TM.log.debug("SIMULATION SUITE CALLS", calls=processed)
|
||||
TM.game_state.set_var("instr.has_issued_instructions", "yes", commit=False)
|
||||
|
||||
TM.emit_status("busy", "Simulation suite altering environment.", as_scene_message=True)
|
||||
compiled = "\n".join(processed)
|
||||
if not self.simulation_reset and compiled:
|
||||
TM.agents.narrator.action_to_narration(
|
||||
action_name="progress_story",
|
||||
narrative_direction=f"The computer calls the following functions:\n\n{compiled}\n\nand the simulation adjusts the environment according to the user's wishes.\n\nWrite the narrative that describes the changes to the player in the context of the simulation starting up. YOU MUST NOT REFERENCE THE COMPUTER.",
|
||||
emit_message=True
|
||||
)
|
||||
|
||||
self.update_world_state = True
|
||||
|
||||
def prepare_calls(self, calls):
|
||||
"""
|
||||
Loops through calls and if a `set_player_name` call and a `set_player_persona` call are both
|
||||
found, ensure that the `set_player_name` call is processed first by moving it in front of the
|
||||
`set_player_persona` call.
|
||||
"""
|
||||
|
||||
set_player_name_call_exists = -1
|
||||
set_player_persona_call_exists = -1
|
||||
|
||||
i = 0
|
||||
for call in calls:
|
||||
if "set_player_name" in call:
|
||||
set_player_name_call_exists = i
|
||||
elif "set_player_persona" in call:
|
||||
set_player_persona_call_exists = i
|
||||
i = i + 1
|
||||
|
||||
if set_player_name_call_exists > -1 and set_player_persona_call_exists > -1:
|
||||
|
||||
if set_player_name_call_exists > set_player_persona_call_exists:
|
||||
calls.insert(set_player_persona_call_exists, calls.pop(set_player_name_call_exists))
|
||||
TM.log.debug("SIMULATION SUITE: prepare calls - moved set_player_persona call", calls=calls)
|
||||
|
||||
return calls
|
||||
|
||||
def process_call(self, call:str) -> str:
|
||||
"""
|
||||
Processes a simulation call
|
||||
|
||||
Simulation alls are pseudo functions that are called by the simulation suite
|
||||
|
||||
We grab the function name by splitting against ( and taking the first element
|
||||
if the SimulationSuite has a method with the name _call_{function_name} then we call it
|
||||
|
||||
if a function name could be found but we do not have a method to call we dont do anything
|
||||
but we still return it as procssed as the AI can still interpret it as something later on
|
||||
"""
|
||||
|
||||
if "(" not in call:
|
||||
return None
|
||||
|
||||
function_name = call.split("(")[0]
|
||||
|
||||
if hasattr(self, f"call_{function_name}"):
|
||||
TM.log.debug("SIMULATION SUITE CALL", call=call, function_name=function_name)
|
||||
|
||||
inject = f"The computer executes the function `{call}`"
|
||||
|
||||
return getattr(self, f"call_{function_name}")(call, inject)
|
||||
|
||||
return call
|
||||
|
||||
|
||||
def call_set_simulation_goal(self, call:str, inject:str) -> str:
|
||||
"""
|
||||
Set's the simulation goal as a permanent pin
|
||||
"""
|
||||
TM.emit_status("busy", "Simulation suite setting goal.", as_scene_message=True)
|
||||
TM.agents.world_state.manager(
|
||||
action_name="save_world_entry",
|
||||
entry_id="sim.goal",
|
||||
text=self.player_message.raw,
|
||||
meta={},
|
||||
pin=True
|
||||
)
|
||||
|
||||
TM.agents.director.log_action(
|
||||
action=parse_sim_call_arguments(call),
|
||||
action_description="The computer sets the goal for the simulation.",
|
||||
)
|
||||
|
||||
return call
|
||||
|
||||
def call_change_environment(self, call:str, inject:str) -> str:
|
||||
"""
|
||||
Simulation changes the environment, this is entirely interpreted by the AI
|
||||
and we dont need to do any logic on our end, so we just return the call
|
||||
"""
|
||||
|
||||
TM.agents.director.log_action(
|
||||
action=parse_sim_call_arguments(call),
|
||||
action_description="The computer changes the environment of the simulation."
|
||||
)
|
||||
|
||||
return call
|
||||
|
||||
|
||||
def call_answer_question(self, call:str, inject:str) -> str:
|
||||
"""
|
||||
The player asked the simulation a query, we need to process this and have
|
||||
the AI produce an answer
|
||||
"""
|
||||
|
||||
TM.agents.narrator.action_to_narration(
|
||||
action_name="progress_story",
|
||||
narrative_direction=f"The computer calls the following function:\n\n{call}\n\nand answers the player's question.",
|
||||
emit_message=True
|
||||
)
|
||||
|
||||
|
||||
def call_set_player_persona(self, call:str, inject:str) -> str:
|
||||
|
||||
"""
|
||||
The simulation suite is altering the player persona
|
||||
"""
|
||||
|
||||
TM.emit_status("busy", "Simulation suite altering user persona.", as_scene_message=True)
|
||||
character_attributes = TM.agents.world_state.extract_character_sheet(
|
||||
name=self.player_character.name, text=inject, alteration_instructions=self.player_message.raw
|
||||
)
|
||||
self.player_character.update(base_attributes=character_attributes)
|
||||
|
||||
character_description = TM.agents.creator.determine_character_description(character=self.player_character)
|
||||
self.player_character.update(description=character_description)
|
||||
TM.log.debug("SIMULATION SUITE: transform player", attributes=character_attributes, description=character_description)
|
||||
|
||||
TM.agents.director.log_action(
|
||||
action=parse_sim_call_arguments(call),
|
||||
action_description="The computer transforms the player persona."
|
||||
)
|
||||
|
||||
return call
|
||||
|
||||
|
||||
def call_set_player_name(self, call:str, inject:str) -> str:
|
||||
|
||||
"""
|
||||
The simulation suite is altering the player name
|
||||
"""
|
||||
|
||||
TM.emit_status("busy", "Simulation suite adjusting user identity.", as_scene_message=True)
|
||||
character_name = TM.agents.creator.determine_character_name(character_name=f"{inject} - What is a fitting name for the player persona? Respond with the current name if it still fits.")
|
||||
TM.log.debug("SIMULATION SUITE: player name", character_name=character_name)
|
||||
if character_name != self.player_character.name:
|
||||
self.player_character.rename(character_name)
|
||||
|
||||
TM.agents.director.log_action(
|
||||
action=parse_sim_call_arguments(call),
|
||||
action_description=f"The computer changes the player's identity to {character_name}."
|
||||
)
|
||||
|
||||
return call
|
||||
|
||||
|
||||
def call_add_ai_character(self, call:str, inject:str) -> str:
|
||||
|
||||
# sometimes the AI will call this function an pass an inanimate object as the parameter
|
||||
# we need to determine if this is the case and just ignore it
|
||||
is_inanimate = TM.client.query_text_eval("does the function add an inanimate object?", call)
|
||||
|
||||
if is_inanimate:
|
||||
TM.log.debug("SIMULATION SUITE: add npc - inanimate object", call=call)
|
||||
return
|
||||
|
||||
# sometimes the AI will ask if the function adds a group of characters, we need to
|
||||
# determine if this is the case
|
||||
adds_group = TM.client.query_text_eval("does the function add a group of characters?", call)
|
||||
|
||||
TM.log.debug("SIMULATION SUITE: add npc", adds_group=adds_group)
|
||||
|
||||
TM.emit_status("busy", "Simulation suite adding character.", as_scene_message=True)
|
||||
|
||||
if not adds_group:
|
||||
character_name = TM.agents.creator.determine_character_name(character_name=f"{inject} - what is the name of the character to be added to the scene? If no name can extracted from the text, extract a short descriptive name instead. Respond only with the name.")
|
||||
else:
|
||||
character_name = TM.agents.creator.determine_character_name(character_name=f"{inject} - what is the name of the group of characters to be added to the scene? If no name can extracted from the text, extract a short descriptive name instead. Respond only with the name.", group=True)
|
||||
|
||||
TM.emit_status("busy", f"Simulation suite adding character: {character_name}", as_scene_message=True)
|
||||
|
||||
TM.log.debug("SIMULATION SUITE: add npc", name=character_name)
|
||||
|
||||
npc = TM.agents.director.persist_character(name=character_name, content=self.player_message.raw+f"\n\n{inject}", determine_name=False)
|
||||
|
||||
self.added_npcs.append(npc.name)
|
||||
|
||||
TM.agents.world_state.manager(
|
||||
action_name="add_detail_reinforcement",
|
||||
character_name=npc.name,
|
||||
question="Goal",
|
||||
instructions=f"Generate a goal for {npc.name}, based on the user's chosen simulation",
|
||||
interval=25,
|
||||
run_immediately=True
|
||||
)
|
||||
|
||||
TM.log.debug("SIMULATION SUITE: added npc", npc=npc)
|
||||
|
||||
TM.agents.visual.generate_character_portrait(character_name=npc.name)
|
||||
|
||||
TM.agents.director.log_action(
|
||||
action=parse_sim_call_arguments(call),
|
||||
action_description=f"The computer adds {npc.name} to the simulation."
|
||||
)
|
||||
|
||||
return call
|
||||
|
||||
|
||||
def call_remove_ai_character(self, call:str, inject:str) -> str:
|
||||
TM.emit_status("busy", "Simulation suite removing character.", as_scene_message=True)
|
||||
|
||||
character_name = TM.agents.creator.determine_character_name(character_name=f"{inject} - what is the name of the character being removed?", allowed_names=TM.scene.npc_character_names())
|
||||
|
||||
npc = TM.scene.get_character(character_name)
|
||||
|
||||
if npc:
|
||||
TM.log.debug("SIMULATION SUITE: remove npc", npc=npc.name)
|
||||
TM.agents.world_state.manager(action_name="deactivate_character", character_name=npc.name)
|
||||
|
||||
TM.agents.director.log_action(
|
||||
action=parse_sim_call_arguments(call),
|
||||
action_description=f"The computer removes {npc.name} from the simulation."
|
||||
)
|
||||
|
||||
return call
|
||||
|
||||
def call_change_ai_character(self, call:str, inject:str) -> str:
|
||||
TM.emit_status("busy", "Simulation suite altering character.", as_scene_message=True)
|
||||
|
||||
character_name = TM.agents.creator.determine_character_name(character_name=f"{inject} - what is the name of the character receiving the changes (before the change)?", allowed_names=TM.scene.npc_character_names())
|
||||
|
||||
if character_name in self.added_npcs:
|
||||
# we dont want to change the character if it was just added
|
||||
return
|
||||
|
||||
character_name_after = TM.agents.creator.determine_character_name(character_name=f"{inject} - what is the name of the character receiving the changes (after the changes)?")
|
||||
|
||||
npc = TM.scene.get_character(character_name)
|
||||
|
||||
if npc:
|
||||
TM.emit_status("busy", f"Changing {character_name} -> {character_name_after}", as_scene_message=True)
|
||||
|
||||
TM.log.debug("SIMULATION SUITE: transform npc", npc=npc)
|
||||
|
||||
character_attributes = TM.agents.world_state.extract_character_sheet(name=npc.name, alteration_instructions=self.player_message.raw)
|
||||
|
||||
npc.update(base_attributes=character_attributes)
|
||||
character_description = TM.agents.creator.determine_character_description(character=npc)
|
||||
|
||||
npc.update(description=character_description)
|
||||
TM.log.debug("SIMULATION SUITE: transform npc", attributes=character_attributes, description=character_description)
|
||||
|
||||
if character_name_after != character_name:
|
||||
npc.rename(character_name_after)
|
||||
|
||||
TM.agents.director.log_action(
|
||||
action=parse_sim_call_arguments(call),
|
||||
action_description=f"The computer transforms {npc.name}."
|
||||
)
|
||||
|
||||
return call
|
||||
|
||||
def call_end_simulation(self, call:str, inject:str) -> str:
|
||||
|
||||
explicit_command = TM.client.query_text_eval("has the player explicitly asked to end the simulation?", self.player_message.raw)
|
||||
|
||||
if explicit_command:
|
||||
TM.emit_status("busy", "Simulation suite ending current simulation.", as_scene_message=True)
|
||||
TM.agents.narrator.action_to_narration(
|
||||
action_name="progress_story",
|
||||
narrative_direction=f"Narrate the computer ending the simulation, dissolving the environment and all artificial characters, erasing all memory of it and finally returning the player to the inactive simulation suite. List of artificial characters: {', '.join(TM.scene.npc_character_names())}. The player is also transformed back to their normal, non-descript persona as the form of {self.player_character.name} ceases to exist.",
|
||||
emit_message=True
|
||||
)
|
||||
TM.scene.restore()
|
||||
|
||||
self.simulation_reset = True
|
||||
|
||||
TM.game_state.unset_var("instr.has_issued_instructions")
|
||||
TM.game_state.unset_var("instr.lastprocessed_call")
|
||||
TM.game_state.unset_var("instr.simulation_started")
|
||||
|
||||
TM.agents.director.log_action(
|
||||
action=parse_sim_call_arguments(call),
|
||||
action_description="The computer ends the simulation."
|
||||
)
|
||||
|
||||
def finalize_round(self):
|
||||
|
||||
if self.update_world_state:
|
||||
self.run_update_world_state()
|
||||
|
||||
if self.player_message_is_instruction:
|
||||
self.player_message.hide()
|
||||
TM.game_state.set_var("instr.lastprocessed_call", self.player_message.id, commit=False)
|
||||
TM.emit_status("success", MSG_PROCESSED_INSTRUCTIONS, as_scene_message=True)
|
||||
|
||||
elif self.player_message and not TM.game_state.has_var("instr.has_issued_instructions"):
|
||||
# simulation started, player message is NOT an instruction, and player has not given
|
||||
# any instructions
|
||||
self.guide_player()
|
||||
|
||||
elif self.player_message and not TM.scene.npc_character_names():
|
||||
# simulation started, player message is NOT an instruction, but there are no npcs to interact with
|
||||
self.narrate_round()
|
||||
|
||||
def guide_player(self):
|
||||
TM.agents.narrator.action_to_narration(
|
||||
action_name="paraphrase",
|
||||
narration=MSG_HELP,
|
||||
emit_message=True
|
||||
)
|
||||
|
||||
def narrate_round(self):
|
||||
TM.agents.narrator.action_to_narration(
|
||||
action_name="progress_story",
|
||||
narrative_direction=PROMPT_NARRATE_ROUND,
|
||||
emit_message=True
|
||||
)
|
||||
|
||||
def run_update_world_state(self, force=False):
|
||||
TM.log.debug("SIMULATION SUITE: update world state", force=force)
|
||||
TM.emit_status("busy", "Simulation suite updating world state.", as_scene_message=True)
|
||||
TM.agents.world_state.update_world_state(force=force)
|
||||
TM.emit_status("success", "Simulation suite updated world state.", as_scene_message=True)
|
||||
|
||||
SimulationSuite().run()
|
||||
@@ -19,6 +19,7 @@ You must at least call one of the following functions:
|
||||
- set_player_name
|
||||
- end_simulation
|
||||
- answer_question
|
||||
- set_simulation_goal
|
||||
|
||||
`add_ai_character` and `change_ai_character` are exclusive if they are targeting the same character.
|
||||
|
||||
@@ -52,14 +53,16 @@ change_ai_character("George is injured")
|
||||
|
||||
Request: Computer, I want to experience a rollercoaster ride with a friend
|
||||
```simulation-stack
|
||||
set_simulation_goal("player experiences a rollercoaster ride")
|
||||
change_environment("theme park, riding a rollercoaster")
|
||||
set_player_persona("young female experiencing rollercoaster ride")
|
||||
set_player_name("Susanne")
|
||||
add_ai_character("a female friend of player named Sarah")
|
||||
```
|
||||
|
||||
Request: Computer, I want to experience the international space station
|
||||
Request: Computer, I want to experience the international space station, to experience the overview effect
|
||||
```simulation-stack
|
||||
set_simulation_goal("player experiences the overview effect")
|
||||
change_environment("international space station")
|
||||
set_player_persona("astronaut experiencing first trip to ISS")
|
||||
set_player_name("George")
|
||||
@@ -110,6 +113,15 @@ Request: Computer, what do you know about the game of thrones?
|
||||
answer_question("what do you know about the game of thrones?")
|
||||
```
|
||||
|
||||
Request: Computer, i want to be a wizard in a dark goblin infested dungeon in a fantasy world, looking for secret treasure and fighting goblins.
|
||||
```simulation-stack
|
||||
set_simulation_goal("player wants to find secret treasure and fight creatures")
|
||||
change_environment("dark dungeon in a fantasy world")
|
||||
set_player_persona("powerful wizard")
|
||||
set_player_name("Lanadel")
|
||||
add_ai_character("a goblin named Gobbo")
|
||||
```
|
||||
|
||||
<|CLOSE_SECTION|>
|
||||
<|SECTION:TASK|>
|
||||
Respond with the simulation stack for the following request:
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
{% set update_world_state = False %}
|
||||
{% set _ = debug("HOLODECK SIMULATION") -%}
|
||||
{% set player_character = scene.get_player_character() %}
|
||||
{% set player_message = scene.last_player_message() %}
|
||||
{% set last_processed = game_state.get_var('instr.last_processed', -1) %}
|
||||
{% set player_message_is_instruction = (player_message and player_message.raw.lower().startswith("computer") and not player_message.hidden) and not player_message.raw.lower().strip() == "computer" and not last_processed >= player_message.id %}
|
||||
{% set simulation_reset = False %}
|
||||
{% if not game_state.has_var('instr.simulation_stopped') %}
|
||||
{# simulation NOT started #}
|
||||
|
||||
{# get last player instruction #}
|
||||
{% if player_message_is_instruction %}
|
||||
{# player message exists #}
|
||||
|
||||
{#% set _ = agent_action("narrator", "action_to_narration", action_name="paraphrase", narration="The computer is processing the request, please wait a moment.", emit_message=True) %#}
|
||||
|
||||
{% set calls = render_and_request(render_template("computer", player_instruction=player_message.raw), dedupe_enabled=False) %}
|
||||
|
||||
{% set _ = debug("HOLODECK simulation calls", calls=calls ) %}
|
||||
{% set processed = make_list() %}
|
||||
|
||||
{% for call in calls.split("\n") %}
|
||||
{% set _ = debug("CALL", call=call, processed=processed) %}
|
||||
{% set inject = "The computer executes the function `"+call+"`" %}
|
||||
{% if call.strip().startswith('change_environment') %}
|
||||
{# change environment #}
|
||||
{% set _ = processed.append(call) %}
|
||||
|
||||
{% elif call.strip().startswith("answer_question") %}
|
||||
{# answert a query #}
|
||||
|
||||
{% set _ = agent_action("narrator", "action_to_narration", action_name="progress_story", narrative_direction="The computer calls the following function:\n"+call+"\nand answers the player's question.", emit_message=True) %}
|
||||
|
||||
|
||||
{% elif call.strip().startswith("set_player_persona") %}
|
||||
{# treansform player #}
|
||||
{% set _ = emit_status("busy", "Simulation suite altering user persona.", as_scene_message=True) %}
|
||||
|
||||
{% set character_attributes = agent_action("world_state", "extract_character_sheet", name=player_character.name, text=player_message.raw)%}
|
||||
|
||||
{% set _ = player_character.update(base_attributes=character_attributes) %}
|
||||
|
||||
{% set character_description = agent_action("creator", "determine_character_description", character=player_character) %}
|
||||
|
||||
{% set _ = player_character.update(description=character_description) %}
|
||||
|
||||
{% set _ = debug("HOLODECK transform player", attributes=character_attributes, description=character_description) %}
|
||||
{% set _ = processed.append(call) %}
|
||||
{% elif call.strip().startswith("set_player_name") %}
|
||||
{# change player name #}
|
||||
{% set _ = emit_status("busy", "Simulation suite adjusting user idenity.", as_scene_message=True) %}
|
||||
{% set character_name = agent_action("creator", "determine_character_name", character_name=inject+" - What is a fitting name for the player persona? Respond with the current name if it still fits.") %}
|
||||
|
||||
{% set _ = debug("HOLODECK player name", character_name=character_name) %}
|
||||
|
||||
{% if character_name != player_character.name %}
|
||||
{% set _ = processed.append(call) %}
|
||||
{% set _ = player_character.rename(character_name) %}
|
||||
{% endif %}
|
||||
{% elif call.strip().startswith("add_ai_character") %}
|
||||
{# add new npc #}
|
||||
|
||||
{% set _ = emit_status("busy", "Simulation suite adding character.", as_scene_message=True) %}
|
||||
{% set character_name = agent_action("creator", "determine_character_name", character_name=inject+" - what is the name of the character to be added to the scene? If no name can extracted from the text, extract a short descriptive name instead. Respond only with the name.") %}
|
||||
|
||||
{% set _ = emit_status("busy", "Simulation suite adding character: "+character_name, as_scene_message=True) %}
|
||||
{% set _ = debug("HOLODECK add npc", name=character_name)%}
|
||||
{% set npc = agent_action("director", "persist_character", name=character_name, content=player_message.raw )%}
|
||||
{% set _ = agent_action("world_state", "manager", action_name="add_detail_reinforcement", character_name=npc.name, question="Goal", instructions="Generate a goal for "+npc.name+", based on the user's chosen simulation", interval=25, run_immediately=True) %}
|
||||
{% set _ = debug("HOLODECK added npc", npc=npc) %}
|
||||
{% set _ = processed.append(call) %}
|
||||
{% set _ = agent_action("visual", "generate_character_portrait", character_name=npc.name) %}
|
||||
{% elif call.strip().startswith("remove_ai_character") %}
|
||||
{# remove npc #}
|
||||
|
||||
{% set _ = emit_status("busy", "Simulation suite removing character.", as_scene_message=True) %}
|
||||
{% set character_name = agent_action("creator", "determine_character_name", character_name=inject+" - what is the name of the character being removed?", allowed_names=scene.npc_character_names) %}
|
||||
|
||||
{% set npc = scene.get_character(character_name) %}
|
||||
|
||||
{% if npc %}
|
||||
{% set _ = debug("HOLODECK remove npc", npc=npc.name) %}
|
||||
{% set _ = agent_action("world_state", "manager", action_name="deactivate_character", character_name=npc.name) %}
|
||||
{% set _ = processed.append(call) %}
|
||||
{% endif %}
|
||||
{% elif call.strip().startswith("change_ai_character") %}
|
||||
{# change existing npc #}
|
||||
|
||||
{% set _ = emit_status("busy", "Simulation suite altering character.", as_scene_message=True) %}
|
||||
{% set character_name = agent_action("creator", "determine_character_name", character_name=inject+" - what is the name of the character receiving the changes (before the change)?", allowed_names=scene.npc_character_names) %}
|
||||
|
||||
{% set character_name_after = agent_action("creator", "determine_character_name", character_name=inject+" - what is the name of the character receiving the changes (after the changes)?") %}
|
||||
|
||||
{% set npc = scene.get_character(character_name) %}
|
||||
|
||||
{% if npc %}
|
||||
{% set _ = emit_status("busy", "Changing "+character_name+" -> "+character_name_after, as_scene_message=True) %}
|
||||
{% set _ = debug("HOLODECK transform npc", npc=npc) %}
|
||||
{% set character_attributes = agent_action("world_state", "extract_character_sheet", name=npc.name, alteration_instructions=player_message.raw)%}
|
||||
{% set _ = npc.update(base_attributes=character_attributes) %}
|
||||
{% set character_description = agent_action("creator", "determine_character_description", character=npc) %}
|
||||
{% set _ = npc.update(description=character_description) %}
|
||||
{% set _ = debug("HOLODECK transform npc", attributes=character_attributes, description=character_description) %}
|
||||
{% set _ = processed.append(call) %}
|
||||
{% if character_name_after != character_name %}
|
||||
{% set _ = npc.rename(character_name_after) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% elif call.strip().startswith("end_simulation") %}
|
||||
{# end simulation #}
|
||||
{% set explicit_command = query_text_eval("has the player explicitly asked to end the simulation?", player_message.raw) %}
|
||||
{% if explicit_command %}
|
||||
{% set _ = emit_status("busy", "Simulation suite ending current simulation.", as_scene_message=True) %}
|
||||
{% set _ = agent_action("narrator", "action_to_narration", action_name="progress_story", narrative_direction="The computer ends the simulation, disolving the environment and all artifical characters, erasing all memory of it and finally returning the player to the inactive simulation suite.List of artificial characters: "+(",".join(scene.npc_character_names))+". The player is also transformed back to their normal persona.", emit_message=True) %}
|
||||
{% set _ = scene.sync_restore() %}
|
||||
{% set _ = agent_action("world_state", "update_world_state", force=True) %}
|
||||
{% set simulation_reset = True %}
|
||||
{% endif %}
|
||||
{% elif "(" in call.strip() %}
|
||||
{# unknown function call, still add it to processed stack so it can be incoorporated in the narration #}
|
||||
{% set _ = processed.append(call) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if processed and not simulation_reset %}
|
||||
{% set _ = game_state.set_var("instr.has_issued_instructions", "yes", commit=False) %}
|
||||
{% set _ = emit_status("busy", "Simulation suite altering environment.", as_scene_message=True) %}
|
||||
{% set update_world_state = True %}
|
||||
{% set _ = agent_action("narrator", "action_to_narration", action_name="progress_story", narrative_direction="The computer calls the following functions:\n"+processed.join("\n")+"\nand the simulation adjusts the environment according to the user's wishes.\n\nWrite the narrative that describes the changes to the player in the context of the simulation starting up.", emit_message=True) %}
|
||||
{% endif %}
|
||||
|
||||
{% elif not game_state.has_var("instr.simulation_started") %}
|
||||
{# no player message yet, start of scenario #}
|
||||
{% set _ = emit_status("busy", "Simulation suite powering up.", as_scene_message=True) %}
|
||||
{% set _ = game_state.set_var("instr.simulation_started", "yes", commit=False) %}
|
||||
{% set _ = agent_action("narrator", "action_to_narration", action_name="progress_story", narrative_direction="Narrate the computer asking the user to state the nature of their desired simulation.", emit_message=False) %}
|
||||
{% set _ = agent_action("narrator", "action_to_narration", action_name="passthrough", narration="Please state your commands by addressing the computer by stating \"Computer,\" followed by an instruction.") %}
|
||||
|
||||
{# pin to make sure characters don't try to interact with the simulation #}
|
||||
{% set _ = agent_action("world_state", "manager", action_name="save_world_entry", entry_id="sim.quarantined", text="Characters in the simulation ARE NOT AWARE OF THE COMPUTER.", meta=make_dict(), pin=True) %}
|
||||
|
||||
{% set _ = emit_status("success", "Simulation suite ready", as_scene_message=True) %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
{# simulation ongoing #}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if update_world_state %}
|
||||
{% set _ = emit_status("busy", "Simulation suite updating world state.", as_scene_message=True) %}
|
||||
{% set _ = agent_action("world_state", "update_world_state", force=True) %}
|
||||
{% endif %}
|
||||
|
||||
{% if not scene.npc_character_names and not simulation_reset %}
|
||||
{# no characters in the scene, see if there are any to add #}
|
||||
{% set npcs = agent_action("director", "persist_characters_from_worldstate", exclude=["computer", "user", "player", "you"]) %}
|
||||
{% for npc in npcs %}
|
||||
{% set _ = agent_action("world_state", "manager", action_name="add_detail_reinforcement", character_name=npc.name, question="Goal", instructions="Generate a goal for the character, based on the user's chosen simulation", interval=25, run_immediately=True) %}
|
||||
{% endfor %}
|
||||
{% if npcs %}
|
||||
{% set _ = agent_action("world_state", "update_world_state", force=True) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if player_message_is_instruction %}
|
||||
{# hide player message to the computer, so its not included in the scene context #}
|
||||
{% set _ = player_message.hide() %}
|
||||
{% set _ = game_state.set_var("instr.last_processed", player_message.id, commit=False) %}
|
||||
{% set _ = emit_status("success", "Simulation suite processed instructions", as_scene_message=True) %}
|
||||
{% elif player_message and not game_state.has_var("instr.has_issued_instructions") %}
|
||||
{# simulation not started, but player message is not an instruction #}
|
||||
{% set _ = agent_action("narrator", "action_to_narration", action_name="paraphrase", narration="Instructions to the simulation computer are only process if the computer is addressed at the beginning of the instruction. Please state your commands by addressing the computer by stating \"Computer,\" followed by an instruction. For example ... \"Computer, i want to experience being on a derelict spaceship.\"", emit_message=True) %}
|
||||
{% elif player_message and not scene.npc_character_names %}
|
||||
{# simulation started, player message is NOT an instruction, but there are no npcs to interact with #}
|
||||
{% set _ = agent_action("narrator", "action_to_narration", action_name="progress_story", narrative_direction="The environment reacts to the player's actions. YOU MUST NOT ACT ON BEHALF OF THE PLAYER. YOU MUST NOT INTERACT WITH THE COMPUTER.", emit_message=True) %}
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user