diff --git a/CHANGELOG.yaml b/CHANGELOG.yaml
index 4e3abde9..769770bb 100644
--- a/CHANGELOG.yaml
+++ b/CHANGELOG.yaml
@@ -1,5 +1,6 @@
0.37.0.dev:
features:
+ - "System Prompt Template Variable: Added {{ system_prompt }} template variable for system prompt overrides. Use it to include the default system prompt within a custom override, at both the app and client level."
- "Manual Scene Direction Turn: Added a button to the director scene tools menu to manually trigger a scene direction turn. Useful when scene direction is enabled but auto progression is off. Supports optional one-off instructions via Ctrl+click."
- "Visual Scene Tools: Organized the visual tools menu into per-character submenus, matching the world scene tools pattern."
- "Section Format: Per-client setting to control how prompt sections are formatted. Choose between Markdown (## headings) and XML ( tags). Found in the client configuration next to the data format setting."
@@ -27,6 +28,7 @@
- "Contextual Generate: Fixed list-type generation prefilling an empty line after '1.', which caused some LLMs to produce empty lists."
- "Advance Time: Fixed toolbar time advancement being completely non-functional due to a missing websocket handler. Also fixed invalid ISO 8601 duration strings for the 1 week and 2 weeks options."
improvements:
+ - "System Prompt Override Indicators: The system prompt override list now shows a pencil icon next to entries that have an active override, making it easy to see which prompts have been customized."
- "Search Strictness: The distance_mod embedding preset value is now a float (was int) with a range of 0.1–2.0, allowing both tighter and looser similarity matching. A 'Search Strictness' slider is now available in the Context Database UI, letting users tune search sensitivity on the fly. Changes persist to the active embedding preset immediately."
- "Embeddings Device Switching: Changing the embeddings device (e.g., CPU to CUDA) no longer requires a restart. The old model is properly released from ChromaDB's class-level cache and GPU memory is freed before loading the new model."
- "Context Formatting: The |condensed template filter no longer permanently compacts multi-line context (e.g., world info, memories, pins) into a single line when sending prompts to the LLM. Formatting is now only compacted temporarily for deduplication comparison and restored to its original multi-line structure afterwards."
diff --git a/src/talemate/client/system_prompts.py b/src/talemate/client/system_prompts.py
index 66551861..dbed704f 100644
--- a/src/talemate/client/system_prompts.py
+++ b/src/talemate/client/system_prompts.py
@@ -167,8 +167,16 @@ class SystemPrompts(pydantic.BaseModel):
key = f"{kind}_decensor" if decensor else kind
- if getattr(self, key):
- return getattr(self, key)
- if self.parent is not None:
- return self.parent.get(kind, decensor)
- return render_prompt(kind, decensor)
+ prompt = getattr(self, key)
+ if prompt:
+ pass
+ elif self.parent is not None:
+ prompt = self.parent.get(kind, decensor)
+ else:
+ prompt = render_prompt(kind, decensor)
+
+ if "{{ system_prompt }}" in prompt:
+ default_prompt = render_prompt(kind, decensor)
+ prompt = prompt.replace("{{ system_prompt }}", default_prompt)
+
+ return prompt
diff --git a/talemate_frontend/src/components/AppConfigPresetsSystemPrompts.vue b/talemate_frontend/src/components/AppConfigPresetsSystemPrompts.vue
index d2aae442..40c37193 100644
--- a/talemate_frontend/src/components/AppConfigPresetsSystemPrompts.vue
+++ b/talemate_frontend/src/components/AppConfigPresetsSystemPrompts.vue
@@ -13,6 +13,9 @@
{{ item.label }}
+
+ mdi-pencil
+
@@ -34,6 +37,9 @@
@blur="$emit('update', {system_prompts: config})"
:label="labelFromValue(selected[0], tab === 'decensor')"
>
+
+ mdi-information-outlineUse {{ system_prompt }} to include the default system prompt in your override.
+
@@ -106,9 +112,7 @@ export default {
return this.tabs.filter(t => t.condition());
},
selectedKey() {
- // selected[0] will hold the kind
- // if tab is decensor, append _decensor
- return this.selected.length > 0 ? this.selected[0]+(this.tab === 'decensor' ? '_decensor' : '') : null;
+ return this.selected.length > 0 ? this.buildKey(this.selected[0]) : null;
}
},
data() {
@@ -148,6 +152,14 @@ export default {
}
},
+ buildKey(value) {
+ return value + (this.tab === 'decensor' ? '_decensor' : '');
+ },
+
+ hasOverride(value) {
+ return !!this.config[this.buildKey(value)];
+ },
+
labelFromValue(value, decensor=false) {
for(let item of this.systemPromptKindList) {
if(item.value === value) {