6 - Reusable Module
Recap
In the previous parts of this guide, we've built a dynamic story premise generator for our Infinity Quest project:
-
Part 1: Created the scene project, imported characters from the original Infinity Quest, and set up basic scene settings.
-
Part 2: Set up the Scene Loop by extending the default Talemate loop, created an event module to hook into scene initialization, and implemented logic to generate a dynamic introduction that only happens once when the scene is first loaded.
-
Part 3: Improved the introduction generation by switching to contextual generation, added a reset mechanism for testing, and implemented random theme generation to guide the premise creation and reduce AI bias.
-
Part 4: Organized our node graph by moving the premise generation logic into a separate submodule, added styling to visually identify agent actions, and improved the module interface.
-
Part 5: Implemented a multi-agent workflow with staging where:
- Stage 1: Generates a random sci-fi theme
- Stage 2: Uses the Summarizer agent to analyze the theme in depth
- Stage 3: Uses the analysis to guide the creation of an introduction text
At this point, we have a fully functional random premise generator for the Infinity Quest project. However, one of the most powerful features of the Talemate node editor is the ability to create modular, reusable components that can be shared across different scenes and projects.
In this part, we'll transform our premise generator from a scene-specific module into a standalone, reusable component that can be plugged into any scene.
6.0 Backup
We're going to be moving and renaming stuff going forward, so you should backup your project.
Either copy the entire scenes/infinity-quest-dynamic
folder somewhere or at least grab the nodes
subfolder.
6.1 Starting Point
We've done quite a bit of work at this point, so lets quickly go over what we have:
Event Module
This module is responsible for generating the dynamic introduction that only happens once when the scene is first loaded.
Scene Loop Extension
An extension of the default Talemate scene loop where we added an instance of the on-scene-init event module.
Premise Generation Module
This module is responsible for generating the a scene introduction based on random sci-fi theme with the help of the Summarizer agent for additional exploration of the concept.
6.2 Plan
In order to make our premise generator a standalone module, there are a few things we need to consider:
- Rename the event module so its less generic as it will be the entry point for the module.
- Right now the premise generator has some hardcoded values that make sense for the Infinity Quest project (sci-fi themed, star trek type of story). We need to be able to expose this from the premise module all the way to the scene loop extension as configurable properties.
- A toggle for turning analyzation on and off.
- Make the module available as a Talemate module, so it can be plugged into any new scene project.
6.1 Renaming the Event Module
Currently there is no good way to rename a module through the node editor. (Still early in the development of the node editor, so this will be added in the future.)
For now the easiest way to rename it is to simply create a copy.
So load the on-scene-init
module and create a copy of it.
Click the CREATE MODULE button and then Copy current.
In the modal change
- Name:
Dynamic Premise
- Registry:
scene/$N
Now load the scene-loop
module and replace the On Scene Init
module with the new Dynamic Premise
module.
Select the On Scene Init
module and press the delete
key.
Then add the Dynamic Premise
module to the scene loop and set the event_name
to scene_loop_init
.
Save!
Save the module.
Start the scene loop to test that everything's still working.
Then find the old on-scene-init
module in the Modules library and press the button to delete it. Confirm the action.
6.2 Exposing a Reset Toggle
We have the node chain that lets us reset the premise generation.
It'd be practical for this to be a simple switch on the event node.
Create a new group somewhere in the module and call it Properties
. Color it cyan
.
Add the following nodes to the group:
Module Property
Set State
Stage
Connect the nodes as follows:
<Module Property>.name
<Set State>.name
<Module Property>.value
<Set State>.value
<Set State>.value
<Stage>.state
Module Property - Properties
- property_name:
reset
- property_type:
bool
- default:
false
Shift
click the title to auto-title it to PROP reset
.
Leave the Set State
node as is, but change its title to SET local.reset
.
Make sure the scope
is set to local
.
Can't auto-title the Set State node in this case
Since we are plugging the name
output of the Module Property
node into the name
input of the Set State
node, auto titling the Set State node currently doesn't work, so do it manually.
In the Stage
node set the following:
- stage:
-1
Shift
click the title to auto-title it to Stage -1
.
Next go back to the Generate Introduction
group and add the following nodes:
Get State
Replace the existing Make Bool
(titled RESET
) node with the Get State
node, connecting it's value output to the Switch.value
input.
<Get State>.value
<Switch>.value
Get State - Properties
- name:
reset
- scope:
local
Shift
click the title to auto-title it to GET local.reset
.
Save!
Save the module.
Confirm that the Dynamic Premise
node now has a reset
property that is a boolean on / off switch.
Turn it on since we will want to test the module still while working on it.
Save!
Save the module.
6.3 Fixing the registry path for the Generate Premise Module
Still in the Dynamic Premise
module, looking at the Generate Premise
node, it currently exposes no properties to edit.
But, hold on, its path still is registered as infinity-quest-dynamic/generatePremise
- that wont do for a reusable module.
So we need to change it.
Create a copy of the module. (Same as before)
This time in the modal you can leave the Name as is, and simply replace the infinity-quest-dynamic
portion of the Registry with scene
so it reads scene/generatePremise
.
Click Continue to create the copy.
Since we are keeping the name the same, it will simply replace the existing generate-premise
module in the library. However, the dynamic-premise
module is still referencing the old generate-premise
module.
Dont restart talemate right now
Currently the old reference is still loaded in talemate, so we can load the dynamic-premise
module without any issues and remove it. Restarting talemate will cause the old reference to be removed and the dynamic premise module may no longer load.
Delete the old Generate Premise
node.
Save!
Save the module.
Add the new Generate Premise
node and connect it like how the old one was connected.
Save!
Save the module.
The node editor can be a bit buggy here (v0.30.0)
It may be that when searching for the new node you will find the old one as well (or even multiples of it). Just make sure you select the one that has the path as scene/generatePremise
.
The issue will go away the next time talemate is restarted.
6.4 Content control inputs
Investigating the current properties
Lets look which things we need to expose to allow us to control what kind of themes can be generated.
<Generate Theme>.<Generate Thematic List>.instructions
This controls the overarching theme topic. (sci-fi currenly)
A list of sci-fi topics. Keep each item short (1-3 words).
<Analyze Theme>.<Theme Analysis Template>.value
The jinja2 prompt template for the theme analysis.
Analyze the following sci-fi theme:
{{theme}}
Provide a detailed exploration of this theme, including:
1. Key concepts or technologies involved
2. Potential storylines or conflicts
3. How it might affect the crew of the Starlight Nomad
Your analysis will be used to set up the premise for the next storyline in the Infinity Quest series.
<Generate Introduction>.<Instruction Template>.value
The prompt template for the introduction generation.
Generate the introduction to a random exciting scenario
for the crew of the Starlight Nomad.
The theme is: "{theme}"
Use the following analysis to guide your creation of the scenario premise:
{theme_analysis}
So looking at the above, it seems we will need:
- A
topic
input that is a string. - A
analysis_instructions
input that is a string
We will also rewrite the templates a bit to make them more flexible.
Input Nodes
Create a new group somewhere in the module and call it Inputs
. Color it blue
.
Add the following nodes to the group:
Input Socket
(x2)Set State
(x2)Stage
First Input Socket - Properties
- input_type:
str
- input_name:
topic
Shift
click the title to auto-title it to IN topic
.
Second Input Socket - Properties
- input_type:
str
- input_name:
analysis_instructions
Shift
click the title to auto-title it to IN analysis_instructions
.
First Set State - Properties
- name:
topic
- scope:
local
Shift
click the title to auto-title it to SET local.topic
.
Second Set State - Properties
- name:
analysis_instructions
- scope:
local
Shift
click the title to auto-title it to SET local.analysis_instructions
.
Stage - Properties
- stage:
-1
Shift
click the title to auto-title it to Stage -1
.
Connect the nodes as follows:
<IN topic>.value
<SET local.topic>.value
<SET local.topic>.value
<Stage>.state
<IN analysis_instructions>.value
<SET local.analysis_instructions>.value
<SET local.analysis_instructions>.value
<Stage>.state_b
Save!
Save the module.
Adjusting the Generate Theme stage
The topic of the theme will be set in local.topic
, we need to get this and incorporate it into the Generate Thematic List
node. We will also change to use the appropriate prompting nodes to build the prompt. So this will now use a jinja2 template syntax.
In the Generate Theme
group add the following nodes:
Get State
Make Text
Prompt from Template
Render Prompt
Dict Set
Get State - Properties
- name:
topic
- scope:
local
Shift
click the title to auto-title it to GET local.topic
.
Make Text - Properties
I am chosing to rewrite the instructions to be a bit more compatible with what a user might type into the topic
input.
Its good to keep in mind that a user doesn't know what the entire prompt looks like, so their input may not always be ideal. Of course if you're just using this for yourself, this matters less.
- value
A list of topics to use for brain storming. The overarching theme is described as "{{ topic }}". Keep each item short (1-3 words). One of these items will be chosen to bootstrap a new story line.
Retitle to Instructions
Connect the nodes as follows:
<GET local.topic>.value
<Dict Set>.value
<GET local.topic>.name
<Dict Set>.key
<Instructions>.value
<Prompt from Template>.template_text
<Dict Set>.dict
<Prompt from Template>.variables
<Prompt from Template>.prompt
<Render Prompt>.prompt
<Render Prompt>.rendered
<Generate Thematic List>.instructions
Save!
Save the module.
Adjusting the Analyze Theme stage
We will do the same for the Analyze Theme
stage, conveniently this is already using Prompt from Template
node, but the template itself is about to get a bit of a makeover, so there is a bit of work ahead of us.
However here I also want to include some extra context in the instructions to help improve the quality of the analysis.
In the Analyze Theme
group add the following nodes:
Get State
(x2)Dict Set
(x2)Template variables
First Get State - Properties
- name:
analysis_instructions
- scope:
local
Shift
click the title to auto-title it to GET local.analysis_instructions
.
Second Get State - Properties
- name:
topic
- scope:
local
Shift
click the title to auto-title it to GET local.topic
.
Theme Analysis Template
Here I want to add the scene description
and the characters description
to the template, thinking it will influence the analysis within the context of the story baseline. Knowing the characters will also help the agent come up with potenial storyline suggestions.
Additionally I am deciding to coerce the response to be a bit more concise and to the point. In my testing I found that the agent was getting a bit verbose and even with a 1024 token limit it was getting cut off.
- value
<|SECTION:STORY BASELINE|> {{ scene.description }} <|SECTION:PROTAGONISTS|> {% for character in scene.characters %} ### {{ character.name }} {{ character.description }} {% endfor %} <|SECTION:CONTEXT OF YOUR TASK|> A topic description of "{{ topic }}" was given and a random theme was picked to bootstrap a new storyline: "{{ theme }}". <|SECTION:TASK|> Analyze the theme "{{ theme }}" in the context of the topic "{{ topic }}". Provide a brief exploration of this theme, including: 1. Key concepts or ideas involved and how they fit the context 2. Potential storylines or conflicts 3. How it might affect the protagonists of the story {% if analysis_instructions %} {{ analysis_instructions }} {% endif %} Keep your analysis concise and to the point. Your analysis will be used to set up the premise for the next storyline in the `{{ scene.name }}` series.
Template variables
Its the Template variables
node that is responsible for adding variables like scene
to the template
scope.
Connect the nodes as follows:
<GET local.analysis_instructions>.value
<Dict Set>.value
<GET local.analysis_instructions>.name
<Dict Set>.key
<GET local.topic>.value
<Dict Set>.value
<GET local.topic>.name
<Dict Set>.key
Chain all three Dict Set
nodes together (the 2 new ones plus the 1 existing one), with each connecting to the dict
input of the next and the last one connecting to the merge_with
input of the Template variables
node.
Then connect the remaining nodes as follows:
<summarizer>.agent
<Template variables>.agent
<Template variables>.agent
<Generate Response>.agent
<Template variables>.variables
<Prompt From Template>.variables
Save!
Save the module.
Adjusting the Generate Introduction stage
This i will leave as is for now, but i will update the Instruction Template
text to remove the infinity quest reference.
Generate the introduction to a random exciting story-line.
The theme is: "{theme}"
Use the following analysis to guide your creation of the scenario premise:
{theme_analysis}
Save!
Save the module.
6.5 - A switch for analysis
My general approach is that i want to be able to turn off long running queries to the agents.
So lets do this for the analysis.
The obvious splace to add this is the state
input of the Generate Response
node in the Analyze Theme
group.
It is currently connected to a Make Bool
node that is set to true
.
To build a switch add the following nodes to the Analyze Theme
group:
Get State
Switch
Get State - Properties
- name:
analysis_enabled
- scope:
local
Shift
click the title to auto-title it to GET local.analysis_enabled
.
Switch - Properties
- pass_through:
false
Connect the nodes as follows:
<GET local.analysis_enabled>.value
<Switch>.value
<Switch>.yes
<Generate Response>.state
Delete the Make Bool
node that was connected to the state
input of the Generate Response
node.
Save!
Save the module.
Next we need to add an Input
node to expose this new analysis_enabled
property.
Add the following nodes to the Inputs
group:
Input Socket
As Bool
Set State
Input Socket - Properties
- input_type:
bool
- input_name:
analysis_enabled
Shift
click the title to auto-title it to IN analysis_enabled
.
As Bool - Properties
- default:
true
Set State - Properties
- name:
analysis_enabled
- scope:
local
Shift
click the title to auto-title it to SET local.analysis_enabled
.
Connect the nodes as follows:
<IN analysis_enabled>.value
<As Bool>.value
<As Bool>.value
<SET local.analysis_enabled>.value
<SET local.analysis_enabled>.value
<Stage>.state_c
Save!
Save the module.
6.6 - Propagating through Dynamic Premise
Good news! Looks like the Generate Premise
node is exposing the 3 new socket inputs we added to the generate-premise
module.
If the Generate Premise
node looks a bit glitchy
If you notice that our Generate Premise
node looks a bit glitchy, where its size is not correct, causing the new widgets to overflow, simply resize it to fix this.
But, we need those properties to be propagated one more level, so someone can simply add the Dynamic Premise
module to their scene loop and then be able to edit everything from there.
Easy enough, just do the now familiar flow of adding three Module Property
nodes, Set State
nodes to the existing Properties
group and connect them to the stage.
analysis_enabled
:bool
- defaulttrue
topic
:str
- default blank stringanalysis_instructions
:text
- default blank string
Save!
Save the module.
Now add three Get State
nodes to the Generate Introduction
group and connect them to the topic
, analysis_instructions
and analysis_enabled
inputs of the Generate Premise
node.
Save!
Save the module.
6.7 - Testing
Confirm the Dynamic Premise
node now is exposing:
reset
- a boolean toggle to reset the premise generation (useful for testing)analysis_instructions
- a text input to control the analysis instructionsanalysis_enabled
- a boolean toggle to control whether the analysis is enabled (defaulttrue
)topic
- a string input to control the topic of the theme
Fill in a topic
.
sci-fi with eldritch and cosmic horror elements
Save!
Save the module.
Start the scene loop to test that everything's still working.
6.8 - Making it a Talemate Module
Currently there is no UX for making a module a Talemate module.
While we work on the tooling for this, here is how to do it manually.
In the talemate
directory find the scenes
directory, and there find the folder for this project.
So if you followed the example to the point, it should be scenes/infinity-quest-dynamic
.
In there find the nodes
directory.
It should have three files in it:
dynamic-premise.json
generate-premise.json
scene-loop.json
Copy both the dynamic-premise.json
and generate-premise.json
files to the templates/modules
directory. (relative to the talemate folder)
Note
If the modules
directory does not exist, create it.
Restart talemate.
To test that this worked, create a new scene project.
Filter the Modules library for premise
and both should be available. (albeit locked for editing)
Extend the scene loop so we can edit it. (Remember how we did this in part 1)
Search for the Dynamic Premise
node and add it to the scene loop.
Looking good!
Keep editing through the original infinity-quest-dynamic scene
Since the Infinity Quest Dynamic
scene still has its own copies of these modules, you can come back to it and make changes.
The load order of modules assures that modules living with the scene take precedence over the ones in the templates/modules
directory.
So a good workflow is to make and test changes in a dedicated scene project and whenever you are happy with it copy the new modules to the templates/modules
directory.
This works as long as the module title and registry values are the same.