Generators
Generators make additional LLM or image-generation calls beyond the normal chat reply. The results go into variables, which you can then use in content rules, expressions, or other classifiers.
Use generators for things like: generating a scene background image when the location changes, producing a short story recap, or creating procedural flavor text.
Generators are extra API calls. Each one adds latency and token cost. Use conditions to prevent unnecessary calls.
Basic shape
Text generator
{
"name": "StoryRecap",
"type": "Text",
"phase": "On Response",
"condition": "turnCount % 5 == 0",
"prompt": "Summarize the last few events in one sentence.",
"includeHistory": true,
"maxTokens": "80",
"updates": [
{ "variable": "recap", "setTo": "{{content}}" }
]
}% is the remainder operator — turnCount % 5 == 0 means "every 5 turns" (when the turn number divides evenly by 5).
Image generator
{
"name": "SceneImage",
"type": "Image",
"phase": "On Response",
"condition": "sceneChanged",
"prompt": "\"A fantasy scene: \" + currentScene",
"aspectRatio": "16:9",
"updates": [
{ "variable": "background", "setTo": "{{content}}" }
]
}Fields shared by all generator types
name
A unique identifier for this generator. Used in dependency references.
type
One of: "Text", "Image", "Image-to-Image". Default: "Text".
phase
When the generator fires:
"On Input"— after the user sends a message, before the bot replies"On Response"— after the bot replies
Note: the schema previously listed an "Initialization" phase option but this was removed from the schema. Use "On Input" with a condition like isNull(someVariable) to initialize variables on first use instead. See Gotchas.
condition
An expression. The generator only runs if this evaluates to truthy (true or a number greater than zero). Always set a condition — generators are expensive.
{ "condition": "sceneChanged" }
{ "condition": "turnCount % 5 == 0" }
{ "condition": "isNull(recap)" }lazy
Default: false. Note: in the current release, this setting does not do anything yet — you can ignore it. The stage always waits for all generators to complete before returning a response, regardless of this flag. (source)
dependencies
A comma-separated list of classifier or generator names that must complete before this generator fires.
prompt
The prompt to send. This is an expression (or a string template). Use template tags to include current state.
{ "prompt": "\"Describe the scene: \" + currentScene" }
{ "prompt": "\"What is {{char}} likely to do next, given mood = \" + mood + \"?\"" }updates
Variable updates applied when the generator finishes. Use {{content}} to reference the generator's output.
"updates": [
{ "variable": "recap", "setTo": "{{content}}" },
{ "variable": "lastGeneratedAt", "setTo": "turnCount" }
]Text generator fields
includeHistory
When true, recent chat history is included in the prompt for context. Increases token usage.
historyContextSize
Default: 0 (use preset). Only relevant when includeHistory is true. A number limiting how much history is sent.
minTokens
Default: "50". The minimum number of tokens to request in the response.
maxTokens
Default: "250". The maximum number of tokens to request. Keep this low for concise outputs like labels or short phrases.
stoppingStrings
A comma-delimited list of strings. If the LLM produces any of them, the response ends there.
{ "stoppingStrings": "\\n,." }retryCondition
Default: "" (never retry, treated as false). If this formula evaluates to true after the generator runs, the generator retries. {{content}} is available here and refers to the generator's output — this is a special case where the generator's output becomes available as {{content}}, overriding the normal rule that template tags only appear inside strings. The stage will retry at most three times.
{ "retryCondition": "isNull({{content}}) or {{content}} == \"\"" }
{ "retryCondition": "not contains({{content}}, \"http\")" }Image generator fields
negativePrompt
Content to exclude from the generated image.
{ "negativePrompt": "blurry, low quality, text" }aspectRatio
Valid values: "21:9", "16:9", "3:2", "5:4", "1:1", "4:5", "2:3", "9:16", "9:21".
{ "aspectRatio": "16:9" }removeBackground
When true, attempts to remove the background from the generated image.
Image-to-Image generator fields
Advanced — skip if you're just getting started
Image-to-Image generation is a specialized feature. The notes below and the known bug are only relevant if you are building bots that transform existing images.
Image-to-Image generators take an existing image and transform it.
sourceImageUrl
An expression that evaluates to a URL of the source image.
{ "sourceImageUrl": "background" }imageToImageType
The transform model to use. Values (case-sensitive, lowercase): "edit", "canny", "face". Default: "edit".
"edit"(Qwen) — general-purpose image editing"canny"(Flux) — edge-guided generation"face"(Flux) — face-swap style transfer
Known bug: the current release reads this from a misspelled key iamgeToImageType in the source code. If you set imageToImageType to "canny" or "face", the stage reads undefined and defaults to "edit". See Gotchas.
Worked examples
A recap generator that fires every five turns
{
"name": "Recap",
"type": "Text",
"phase": "On Response",
"condition": "turnCount % 5 == 0",
"prompt": "\"In one sentence, summarize the most recent events in this conversation.\"",
"includeHistory": true,
"maxTokens": "80",
"stoppingStrings": "\\n",
"updates": [
{ "variable": "recap", "setTo": "{{content}}" }
]
}A scene background image gated on a flag
{
"name": "BackgroundImage",
"type": "Image",
"phase": "On Response",
"condition": "sceneChanged",
"prompt": "\"Fantasy scene, detailed illustration: \" + currentScene + \". No text, no UI elements.\"",
"negativePrompt": "text, letters, watermark, ui",
"aspectRatio": "16:9",
"updates": [
{ "variable": "background", "setTo": "{{content}}" }
]
}The background variable has a special meaning — Statosphere uses it to set the chat background. See Background Variable.