mirror of
https://github.com/vegu-ai/talemate.git
synced 2026-09-01 19:48:52 +02:00
move scene message nodes to separate module
This commit is contained in:
@@ -3,6 +3,7 @@ import talemate.game.engine.nodes.command # noqa: F401
|
||||
import talemate.game.engine.nodes.logic # noqa: F401
|
||||
import talemate.game.engine.nodes.state # noqa: F401
|
||||
import talemate.game.engine.nodes.scene # noqa: F401
|
||||
import talemate.game.engine.nodes.scene_messages # noqa: F401
|
||||
import talemate.game.engine.nodes.scene_intent # noqa: F401
|
||||
import talemate.game.engine.nodes.world_state # noqa: F401
|
||||
import talemate.game.engine.nodes.run # noqa: F401
|
||||
|
||||
@@ -777,333 +777,6 @@ class UnpackInteractionState(Node):
|
||||
)
|
||||
|
||||
|
||||
@register("scene/message/CharacterMessage")
|
||||
class CharacterMessage(Node):
|
||||
"""
|
||||
Creates a character message from a character and a message
|
||||
|
||||
Inputs:
|
||||
|
||||
- character: The character object
|
||||
- message: The message to send
|
||||
- source: The source of the message - player or ai, so whether the message is result of user input or AI generated
|
||||
- from_choice: For player messages this indicates that the message was generated from a choice selection, for ai sourced messages this indicates the instruction that was followed
|
||||
|
||||
Properties:
|
||||
|
||||
- source: The source of the message
|
||||
|
||||
Outputs:
|
||||
|
||||
- message: The message object (this is a scene_message.CharacterMessage instance)
|
||||
"""
|
||||
|
||||
class Fields:
|
||||
source = PropertyField(
|
||||
name="source",
|
||||
description="The source of the message",
|
||||
type="str",
|
||||
default="player",
|
||||
choices=[
|
||||
"player",
|
||||
"ai",
|
||||
],
|
||||
)
|
||||
|
||||
def __init__(self, title="Character Message", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("character", socket_type="character")
|
||||
self.add_input("message", socket_type="str")
|
||||
self.add_input("source", socket_type="str", optional=True)
|
||||
self.add_input("from_choice", socket_type="str", optional=True)
|
||||
|
||||
self.set_property("source", "player")
|
||||
|
||||
self.add_output("message", socket_type="message_object")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
character: "Character" = self.get_input_value("character")
|
||||
message = self.get_input_value("message")
|
||||
source = self.get_input_value("source")
|
||||
from_choice = self.get_input_value("from_choice")
|
||||
|
||||
extra = {}
|
||||
|
||||
if isinstance(from_choice, str):
|
||||
extra["from_choice"] = from_choice
|
||||
|
||||
# Capture the character's current avatar at message creation time
|
||||
# (not default avatar - messages only use current_avatar if set)
|
||||
if character.current_avatar:
|
||||
extra["asset_id"] = character.current_avatar
|
||||
extra["asset_type"] = "avatar"
|
||||
|
||||
# prefix name: if not already prefixed
|
||||
if not message.startswith(f"{character.name}: "):
|
||||
message = f"{character.name}: {message}"
|
||||
|
||||
message = scene_message.CharacterMessage(message, source=source, **extra)
|
||||
|
||||
self.set_output_values({"message": message})
|
||||
|
||||
|
||||
@register("scene/message/NarratorMessage")
|
||||
class NarratorMessage(Node):
|
||||
"""
|
||||
Creates a narrator message
|
||||
|
||||
Inputs:
|
||||
|
||||
- message: The message to send
|
||||
- source: The source of the message - player or ai, so whether the message is result of user input or AI generated
|
||||
- meta: A dictionary of meta information to attach to the message. This will generally be arguments and function name that was called on the narrator agent to generate the message and will be used when regenerating the message.
|
||||
|
||||
Properties:
|
||||
|
||||
- source: The source of the message
|
||||
|
||||
Outputs:
|
||||
|
||||
- message: The message object (this is a scene_message.NarratorMessage instance)
|
||||
"""
|
||||
|
||||
class Fields:
|
||||
source = PropertyField(
|
||||
name="source",
|
||||
description="The source of the message",
|
||||
type="str",
|
||||
default="ai",
|
||||
choices=[
|
||||
"player",
|
||||
"ai",
|
||||
],
|
||||
)
|
||||
|
||||
def __init__(self, title="Narrator Message", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("message", socket_type="str")
|
||||
self.add_input("source", socket_type="str", optional=True)
|
||||
self.add_input("meta", socket_type="dict", optional=True)
|
||||
|
||||
self.set_property("source", "ai")
|
||||
|
||||
self.add_output("message", socket_type="message_object")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
message = self.get_input_value("message")
|
||||
source = self.get_input_value("source")
|
||||
meta = self.get_input_value("meta")
|
||||
|
||||
extra = {}
|
||||
|
||||
if meta and isinstance(meta, dict):
|
||||
extra["meta"] = meta
|
||||
|
||||
message = scene_message.NarratorMessage(message, source=source, **extra)
|
||||
|
||||
self.set_output_values({"message": message})
|
||||
|
||||
|
||||
@register("scene/message/DirectorMessage")
|
||||
class DirectorMessage(Node):
|
||||
"""
|
||||
Creates a director message
|
||||
|
||||
Inputs:
|
||||
|
||||
- message: The message to send
|
||||
- source: The source of the message - player or ai, so whether the message is result of user input or AI generated
|
||||
- meta: A dictionary of meta information to attach to the message. Can hold the character name that the message is related to.
|
||||
- character: The character object that the message is related to
|
||||
|
||||
Properties:
|
||||
|
||||
- source: The source of the message
|
||||
- action: Describes the director action
|
||||
|
||||
Outputs:
|
||||
|
||||
- message: The message object (this is a scene_message.DirectorMessage instance)
|
||||
"""
|
||||
|
||||
class Fields:
|
||||
source = PropertyField(
|
||||
name="source",
|
||||
description="The source of the message",
|
||||
type="str",
|
||||
default="ai",
|
||||
choices=[
|
||||
"player",
|
||||
"ai",
|
||||
],
|
||||
)
|
||||
|
||||
action = PropertyField(
|
||||
name="action",
|
||||
description="Describes the director action",
|
||||
type="str",
|
||||
default="actor_instruction",
|
||||
choices=[
|
||||
"actor_instruction",
|
||||
"user_direction",
|
||||
],
|
||||
)
|
||||
|
||||
subtype = PropertyField(
|
||||
name="subtype",
|
||||
description="The subtype of the director message, used for further categorization of the message",
|
||||
type="str",
|
||||
default=UNRESOLVED,
|
||||
choices=[
|
||||
"function_call",
|
||||
"user_direction",
|
||||
],
|
||||
)
|
||||
|
||||
def __init__(self, title="Director Message", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("message", socket_type="str")
|
||||
self.add_input("source", socket_type="str", optional=True)
|
||||
self.add_input("meta", socket_type="dict", optional=True)
|
||||
self.add_input("character", socket_type="character", optional=True)
|
||||
self.add_input("action", socket_type="str", optional=True)
|
||||
self.add_input("subtype", socket_type="str", optional=True)
|
||||
|
||||
self.set_property("source", "ai")
|
||||
self.set_property("action", "actor_instruction")
|
||||
self.set_property("subtype", UNRESOLVED)
|
||||
|
||||
self.add_output("message", socket_type="message_object")
|
||||
self.add_output("source", socket_type="str")
|
||||
self.add_output("meta", socket_type="dict")
|
||||
self.add_output("character", socket_type="character")
|
||||
self.add_output("action", socket_type="str")
|
||||
self.add_output("subtype", socket_type="str")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
message = self.normalized_input_value("message")
|
||||
source = self.normalized_input_value("source")
|
||||
action = self.normalized_input_value("action")
|
||||
meta = self.normalized_input_value("meta")
|
||||
subtype = self.normalized_input_value("subtype")
|
||||
character: "Character" = self.normalized_input_value("character")
|
||||
|
||||
extra = {}
|
||||
|
||||
if meta and isinstance(meta, dict):
|
||||
extra["meta"] = meta
|
||||
|
||||
message = scene_message.DirectorMessage(
|
||||
message, source=source, action=action, subtype=subtype, **extra
|
||||
)
|
||||
|
||||
if character is not None:
|
||||
message.set_meta(character=character.name)
|
||||
|
||||
self.set_output_values(
|
||||
{
|
||||
"message": message,
|
||||
"source": source,
|
||||
"meta": meta,
|
||||
"character": character,
|
||||
"action": action,
|
||||
"subtype": subtype,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@register("scene/message/UnpackMeta")
|
||||
class UnpackMessageMeta(Node):
|
||||
"""
|
||||
Unpacks a message meta dictionary
|
||||
into arguments
|
||||
|
||||
Inputs:
|
||||
|
||||
- meta: The meta dictionary
|
||||
|
||||
Outputs:
|
||||
|
||||
- agent_name: The agent name
|
||||
- function_name: The function name
|
||||
- arguments: The arguments dictionary
|
||||
"""
|
||||
|
||||
def __init__(self, title="Unpack Message Meta", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("meta", socket_type="dict")
|
||||
self.add_output("agent_name", socket_type="str")
|
||||
self.add_output("function_name", socket_type="str")
|
||||
self.add_output("arguments", socket_type="dict")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
meta = self.get_input_value("meta")
|
||||
|
||||
self.set_output_values(
|
||||
{
|
||||
"agent_name": meta["agent"],
|
||||
"function_name": meta["function"],
|
||||
"arguments": meta.get("arguments", {}).copy(),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@register("scene/message/ToggleMessageContextVisibility")
|
||||
class ToggleMessageContextVisibility(Node):
|
||||
"""
|
||||
Hide or show a message. Hidden messages are not displayed to the AI.
|
||||
|
||||
Inputs:
|
||||
|
||||
- message: The message object
|
||||
|
||||
Properties:
|
||||
|
||||
- hidden: Whether the message is hidden
|
||||
|
||||
Outputs:
|
||||
|
||||
- message: The message object
|
||||
"""
|
||||
|
||||
class Fields:
|
||||
hidden = PropertyField(
|
||||
name="hidden",
|
||||
description="Whether the message is hidden",
|
||||
type="bool",
|
||||
default=False,
|
||||
)
|
||||
|
||||
def __init__(self, title="Toggle Message Context Visibility", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("message", socket_type="message_object")
|
||||
|
||||
self.set_property("hidden", False)
|
||||
|
||||
self.add_output("message", socket_type="message_object")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
message = self.require_input("message")
|
||||
hidden = self.get_property("hidden")
|
||||
|
||||
if hidden:
|
||||
message.hide()
|
||||
else:
|
||||
message.unhide()
|
||||
|
||||
self.set_output_values({"message": message})
|
||||
|
||||
|
||||
@register("input/WaitForInput")
|
||||
class WaitForInput(Node):
|
||||
"""
|
||||
|
||||
340
src/talemate/game/engine/nodes/scene_messages.py
Normal file
340
src/talemate/game/engine/nodes/scene_messages.py
Normal file
@@ -0,0 +1,340 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .core import (
|
||||
Node,
|
||||
GraphState,
|
||||
UNRESOLVED,
|
||||
PropertyField,
|
||||
)
|
||||
from .registry import register
|
||||
import talemate.scene_message as scene_message
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from talemate.character import Character
|
||||
|
||||
|
||||
@register("scene/message/CharacterMessage")
|
||||
class CharacterMessage(Node):
|
||||
"""
|
||||
Creates a character message from a character and a message
|
||||
|
||||
Inputs:
|
||||
|
||||
- character: The character object
|
||||
- message: The message to send
|
||||
- source: The source of the message - player or ai, so whether the message is result of user input or AI generated
|
||||
- from_choice: For player messages this indicates that the message was generated from a choice selection, for ai sourced messages this indicates the instruction that was followed
|
||||
|
||||
Properties:
|
||||
|
||||
- source: The source of the message
|
||||
|
||||
Outputs:
|
||||
|
||||
- message: The message object (this is a scene_message.CharacterMessage instance)
|
||||
"""
|
||||
|
||||
class Fields:
|
||||
source = PropertyField(
|
||||
name="source",
|
||||
description="The source of the message",
|
||||
type="str",
|
||||
default="player",
|
||||
choices=[
|
||||
"player",
|
||||
"ai",
|
||||
],
|
||||
)
|
||||
|
||||
def __init__(self, title="Character Message", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("character", socket_type="character")
|
||||
self.add_input("message", socket_type="str")
|
||||
self.add_input("source", socket_type="str", optional=True)
|
||||
self.add_input("from_choice", socket_type="str", optional=True)
|
||||
|
||||
self.set_property("source", "player")
|
||||
|
||||
self.add_output("message", socket_type="message_object")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
character: "Character" = self.get_input_value("character")
|
||||
message = self.get_input_value("message")
|
||||
source = self.get_input_value("source")
|
||||
from_choice = self.get_input_value("from_choice")
|
||||
|
||||
extra = {}
|
||||
|
||||
if isinstance(from_choice, str):
|
||||
extra["from_choice"] = from_choice
|
||||
|
||||
# Capture the character's current avatar at message creation time
|
||||
# (not default avatar - messages only use current_avatar if set)
|
||||
if character.current_avatar:
|
||||
extra["asset_id"] = character.current_avatar
|
||||
extra["asset_type"] = "avatar"
|
||||
|
||||
# prefix name: if not already prefixed
|
||||
if not message.startswith(f"{character.name}: "):
|
||||
message = f"{character.name}: {message}"
|
||||
|
||||
message = scene_message.CharacterMessage(message, source=source, **extra)
|
||||
|
||||
self.set_output_values({"message": message})
|
||||
|
||||
|
||||
@register("scene/message/NarratorMessage")
|
||||
class NarratorMessage(Node):
|
||||
"""
|
||||
Creates a narrator message
|
||||
|
||||
Inputs:
|
||||
|
||||
- message: The message to send
|
||||
- source: The source of the message - player or ai, so whether the message is result of user input or AI generated
|
||||
- meta: A dictionary of meta information to attach to the message. This will generally be arguments and function name that was called on the narrator agent to generate the message and will be used when regenerating the message.
|
||||
|
||||
Properties:
|
||||
|
||||
- source: The source of the message
|
||||
|
||||
Outputs:
|
||||
|
||||
- message: The message object (this is a scene_message.NarratorMessage instance)
|
||||
"""
|
||||
|
||||
class Fields:
|
||||
source = PropertyField(
|
||||
name="source",
|
||||
description="The source of the message",
|
||||
type="str",
|
||||
default="ai",
|
||||
choices=[
|
||||
"player",
|
||||
"ai",
|
||||
],
|
||||
)
|
||||
|
||||
def __init__(self, title="Narrator Message", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("message", socket_type="str")
|
||||
self.add_input("source", socket_type="str", optional=True)
|
||||
self.add_input("meta", socket_type="dict", optional=True)
|
||||
|
||||
self.set_property("source", "ai")
|
||||
|
||||
self.add_output("message", socket_type="message_object")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
message = self.get_input_value("message")
|
||||
source = self.get_input_value("source")
|
||||
meta = self.get_input_value("meta")
|
||||
|
||||
extra = {}
|
||||
|
||||
if meta and isinstance(meta, dict):
|
||||
extra["meta"] = meta
|
||||
|
||||
message = scene_message.NarratorMessage(message, source=source, **extra)
|
||||
|
||||
self.set_output_values({"message": message})
|
||||
|
||||
|
||||
@register("scene/message/DirectorMessage")
|
||||
class DirectorMessage(Node):
|
||||
"""
|
||||
Creates a director message
|
||||
|
||||
Inputs:
|
||||
|
||||
- message: The message to send
|
||||
- source: The source of the message - player or ai, so whether the message is result of user input or AI generated
|
||||
- meta: A dictionary of meta information to attach to the message. Can hold the character name that the message is related to.
|
||||
- character: The character object that the message is related to
|
||||
|
||||
Properties:
|
||||
|
||||
- source: The source of the message
|
||||
- action: Describes the director action
|
||||
|
||||
Outputs:
|
||||
|
||||
- message: The message object (this is a scene_message.DirectorMessage instance)
|
||||
"""
|
||||
|
||||
class Fields:
|
||||
source = PropertyField(
|
||||
name="source",
|
||||
description="The source of the message",
|
||||
type="str",
|
||||
default="ai",
|
||||
choices=[
|
||||
"player",
|
||||
"ai",
|
||||
],
|
||||
)
|
||||
|
||||
action = PropertyField(
|
||||
name="action",
|
||||
description="Describes the director action",
|
||||
type="str",
|
||||
default="actor_instruction",
|
||||
choices=[
|
||||
"actor_instruction",
|
||||
"user_direction",
|
||||
],
|
||||
)
|
||||
|
||||
subtype = PropertyField(
|
||||
name="subtype",
|
||||
description="The subtype of the director message, used for further categorization of the message",
|
||||
type="str",
|
||||
default=UNRESOLVED,
|
||||
choices=[
|
||||
"function_call",
|
||||
"user_direction",
|
||||
],
|
||||
)
|
||||
|
||||
def __init__(self, title="Director Message", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("message", socket_type="str")
|
||||
self.add_input("source", socket_type="str", optional=True)
|
||||
self.add_input("meta", socket_type="dict", optional=True)
|
||||
self.add_input("character", socket_type="character", optional=True)
|
||||
self.add_input("action", socket_type="str", optional=True)
|
||||
self.add_input("subtype", socket_type="str", optional=True)
|
||||
|
||||
self.set_property("source", "ai")
|
||||
self.set_property("action", "actor_instruction")
|
||||
self.set_property("subtype", UNRESOLVED)
|
||||
|
||||
self.add_output("message", socket_type="message_object")
|
||||
self.add_output("source", socket_type="str")
|
||||
self.add_output("meta", socket_type="dict")
|
||||
self.add_output("character", socket_type="character")
|
||||
self.add_output("action", socket_type="str")
|
||||
self.add_output("subtype", socket_type="str")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
message = self.normalized_input_value("message")
|
||||
source = self.normalized_input_value("source")
|
||||
action = self.normalized_input_value("action")
|
||||
meta = self.normalized_input_value("meta")
|
||||
subtype = self.normalized_input_value("subtype")
|
||||
character: "Character" = self.normalized_input_value("character")
|
||||
|
||||
extra = {}
|
||||
|
||||
if meta and isinstance(meta, dict):
|
||||
extra["meta"] = meta
|
||||
|
||||
message = scene_message.DirectorMessage(
|
||||
message, source=source, action=action, subtype=subtype, **extra
|
||||
)
|
||||
|
||||
if character is not None:
|
||||
message.set_meta(character=character.name)
|
||||
|
||||
self.set_output_values(
|
||||
{
|
||||
"message": message,
|
||||
"source": source,
|
||||
"meta": meta,
|
||||
"character": character,
|
||||
"action": action,
|
||||
"subtype": subtype,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@register("scene/message/UnpackMeta")
|
||||
class UnpackMessageMeta(Node):
|
||||
"""
|
||||
Unpacks a message meta dictionary
|
||||
into arguments
|
||||
|
||||
Inputs:
|
||||
|
||||
- meta: The meta dictionary
|
||||
|
||||
Outputs:
|
||||
|
||||
- agent_name: The agent name
|
||||
- function_name: The function name
|
||||
- arguments: The arguments dictionary
|
||||
"""
|
||||
|
||||
def __init__(self, title="Unpack Message Meta", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("meta", socket_type="dict")
|
||||
self.add_output("agent_name", socket_type="str")
|
||||
self.add_output("function_name", socket_type="str")
|
||||
self.add_output("arguments", socket_type="dict")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
meta = self.get_input_value("meta")
|
||||
|
||||
self.set_output_values(
|
||||
{
|
||||
"agent_name": meta["agent"],
|
||||
"function_name": meta["function"],
|
||||
"arguments": meta.get("arguments", {}).copy(),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@register("scene/message/ToggleMessageContextVisibility")
|
||||
class ToggleMessageContextVisibility(Node):
|
||||
"""
|
||||
Hide or show a message. Hidden messages are not displayed to the AI.
|
||||
|
||||
Inputs:
|
||||
|
||||
- message: The message object
|
||||
|
||||
Properties:
|
||||
|
||||
- hidden: Whether the message is hidden
|
||||
|
||||
Outputs:
|
||||
|
||||
- message: The message object
|
||||
"""
|
||||
|
||||
class Fields:
|
||||
hidden = PropertyField(
|
||||
name="hidden",
|
||||
description="Whether the message is hidden",
|
||||
type="bool",
|
||||
default=False,
|
||||
)
|
||||
|
||||
def __init__(self, title="Toggle Message Context Visibility", **kwargs):
|
||||
super().__init__(title=title, **kwargs)
|
||||
|
||||
def setup(self):
|
||||
self.add_input("message", socket_type="message_object")
|
||||
|
||||
self.set_property("hidden", False)
|
||||
|
||||
self.add_output("message", socket_type="message_object")
|
||||
|
||||
async def run(self, state: GraphState):
|
||||
message = self.require_input("message")
|
||||
hidden = self.get_property("hidden")
|
||||
|
||||
if hidden:
|
||||
message.hide()
|
||||
else:
|
||||
message.unhide()
|
||||
|
||||
self.set_output_values({"message": message})
|
||||
@@ -23,9 +23,7 @@ from talemate.game.engine.nodes.core import (
|
||||
)
|
||||
from talemate.game.engine.nodes.scene import (
|
||||
ActivateCharacter,
|
||||
CharacterMessage as CharacterMessageNode,
|
||||
DeactivateCharacter,
|
||||
DirectorMessage as DirectorMessageNode,
|
||||
GetCharacter,
|
||||
GetCharacterAttribute,
|
||||
GetCharacterDescription,
|
||||
@@ -41,7 +39,6 @@ from talemate.game.engine.nodes.scene import (
|
||||
IsPlayerCharacter,
|
||||
ListCharacters,
|
||||
MakeCharacter,
|
||||
NarratorMessage as NarratorMessageNode,
|
||||
RemoveAllCharacters,
|
||||
RemoveCharacter,
|
||||
RestoreScene,
|
||||
@@ -53,14 +50,19 @@ from talemate.game.engine.nodes.scene import (
|
||||
SetDescription,
|
||||
SetIntroduction,
|
||||
SetTitle,
|
||||
ToggleMessageContextVisibility,
|
||||
TriggerGameLoopActorIter,
|
||||
UnpackCharacter,
|
||||
UnpackInteractionState,
|
||||
UnpackMessageMeta,
|
||||
UpdateCharacterData,
|
||||
WaitForInput,
|
||||
)
|
||||
from talemate.game.engine.nodes.scene_messages import (
|
||||
CharacterMessage as CharacterMessageNode,
|
||||
DirectorMessage as DirectorMessageNode,
|
||||
NarratorMessage as NarratorMessageNode,
|
||||
ToggleMessageContextVisibility,
|
||||
UnpackMessageMeta,
|
||||
)
|
||||
import talemate.events as events
|
||||
import talemate.scene_message as scene_message
|
||||
|
||||
|
||||
Reference in New Issue
Block a user