mirror of
https://github.com/vegu-ai/talemate.git
synced 2026-08-29 10:08:58 +02:00
Unify tracked-state quick actions into a single Track State action (#72)
* feature(world-state): unify tracked-state quick actions into a single Track State action * refactor(world-state): address PR review - drop unused character prop, rename defaultInsert, remove comment noise
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
- "MistralAI Client: Added a Concurrent Inference toggle so batch operations can dispatch multiple requests in parallel. Off by default."
|
||||
- "Text-Generation-WebUI Client: Added an 'API handles prompt template' toggle. When enabled, requests go to the chat/completions API and text-generation-webui applies the model's prompt template; response pre-filling (coercion) keeps working via the API's continue_ mechanism, and reasoning-model thinking is captured automatically without needing a reasoning pattern. Off by default."
|
||||
- "llama.cpp Client: Added an 'API handles prompt template' toggle. When enabled, prompts are rendered through the server's /apply-template endpoint using the model's built-in chat template; response pre-filling (coercion) and reasoning keep working, and thinking-capable templates are asked not to think when reasoning is disabled. Off by default."
|
||||
- "Track State: The World State scene tool menu's two separate 'Add tracked world state' and 'Add tracked character state' actions are now a single 'Track state' action. The modal itself lets you choose the target — the world or a specific character — before describing what to track, and the context attachment default and 'Require character active' option adapt to the choice."
|
||||
fixes:
|
||||
- "OpenRouter Client: A failed model/provider list fetch at startup no longer sticks until the server is restarted — later config saves and client status refreshes now retry it. Setting the API key for the first time during initial setup also correctly triggers the provider fetch."
|
||||
- "Generation Error Dialog: When several generations failed at the same time (e.g. an API throttle hitting both a summarization and a background task), only the most recent error could be answered — the earlier generation was never resumed and its result (such as a scene summary) was silently lost. Error dialogs are now queued and answered one after another, and pending dialogs are cancelled cleanly when the scene is unloaded or the frontend disconnects."
|
||||
|
||||
@@ -7,16 +7,12 @@
|
||||
{{ description }}
|
||||
</v-alert>
|
||||
|
||||
<v-alert v-if="character" density="compact" icon="mdi-account" variant="text" color="grey" class="mb-2">
|
||||
{{ character }}
|
||||
</v-alert>
|
||||
|
||||
<v-select
|
||||
v-if="characters.length > 0 && !character"
|
||||
v-model="selectedCharacter"
|
||||
:items="characters"
|
||||
label="Character"
|
||||
prepend-inner-icon="mdi-account"
|
||||
v-if="showTargetSelector"
|
||||
v-model="selectedTarget"
|
||||
:items="targetItems"
|
||||
label="Track state for"
|
||||
prepend-inner-icon="mdi-target"
|
||||
></v-select>
|
||||
|
||||
<v-text-field
|
||||
@@ -64,13 +60,15 @@
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" variant="text" prepend-icon="mdi-text-box-plus" @click="create" :disabled="!question || (characters.length > 0 && !effectiveCharacter)">Create</v-btn>
|
||||
<v-btn color="primary" variant="text" prepend-icon="mdi-text-box-plus" @click="create" :disabled="!question || !hasTargetSelection">Create</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const WORLD_TARGET = '__world__';
|
||||
|
||||
export default {
|
||||
name: 'QuickCreateStateReinforcement',
|
||||
props: {
|
||||
@@ -82,10 +80,6 @@ export default {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
character: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
characters: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
@@ -94,7 +88,17 @@ export default {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
defaultInsert: {
|
||||
// When true the target selector offers "World" alongside the characters,
|
||||
// so a single modal can create either a world or a character state.
|
||||
allowWorld: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
characterDefaultInsert: {
|
||||
type: String,
|
||||
default: 'never',
|
||||
},
|
||||
worldDefaultInsert: {
|
||||
type: String,
|
||||
default: 'never',
|
||||
},
|
||||
@@ -108,33 +112,75 @@ export default {
|
||||
dialog: false,
|
||||
question: '',
|
||||
interval: this.defaultInterval,
|
||||
insert: this.defaultInsert,
|
||||
insert: this.allowWorld ? this.worldDefaultInsert : this.characterDefaultInsert,
|
||||
instructions: '',
|
||||
requireActive: true,
|
||||
selectedCharacter: '',
|
||||
selectedTarget: this.allowWorld ? WORLD_TARGET : '',
|
||||
}
|
||||
},
|
||||
emits: ['create'],
|
||||
computed: {
|
||||
showTargetSelector() {
|
||||
return this.allowWorld || this.characters.length > 0;
|
||||
},
|
||||
targetItems() {
|
||||
let items = this.characters.map(name => ({
|
||||
title: name,
|
||||
value: name,
|
||||
props: { prependIcon: 'mdi-account' },
|
||||
}));
|
||||
if (this.allowWorld) {
|
||||
items.unshift({
|
||||
title: 'World',
|
||||
value: WORLD_TARGET,
|
||||
props: { prependIcon: 'mdi-earth' },
|
||||
});
|
||||
}
|
||||
return items;
|
||||
},
|
||||
// The world is the target when it is explicitly selected, or when there
|
||||
// are no characters to choose from at all.
|
||||
isWorldTarget() {
|
||||
return this.selectedTarget === WORLD_TARGET || this.characters.length === 0;
|
||||
},
|
||||
effectiveCharacter() {
|
||||
return this.character || this.selectedCharacter;
|
||||
return this.selectedTarget === WORLD_TARGET ? '' : this.selectedTarget;
|
||||
},
|
||||
hasTargetSelection() {
|
||||
if (!this.showTargetSelector) {
|
||||
return true;
|
||||
}
|
||||
return !!this.selectedTarget;
|
||||
},
|
||||
availableInsertionModes() {
|
||||
if (this.effectiveCharacter) {
|
||||
return this.insertionModes;
|
||||
// conversation-context only makes sense inside a character's own context.
|
||||
if (this.isWorldTarget) {
|
||||
return this.insertionModes.filter(mode => mode.value !== 'conversation-context');
|
||||
}
|
||||
return this.insertionModes.filter(mode => mode.value !== 'conversation-context');
|
||||
return this.insertionModes;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// Keep the insertion mode aligned with the selected target so switching
|
||||
// between World and a character resets to that target's sensible default
|
||||
// (and never leaves an invalid mode like conversation-context on world).
|
||||
isWorldTarget() {
|
||||
this.insert = this.insertDefaultForTarget();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
insertDefaultForTarget() {
|
||||
return this.isWorldTarget ? this.worldDefaultInsert : this.characterDefaultInsert;
|
||||
},
|
||||
|
||||
open() {
|
||||
this.dialog = true;
|
||||
this.question = '';
|
||||
this.interval = this.defaultInterval;
|
||||
this.insert = this.defaultInsert;
|
||||
this.instructions = '';
|
||||
this.requireActive = true;
|
||||
this.selectedCharacter = '';
|
||||
this.selectedTarget = this.allowWorld ? WORLD_TARGET : '';
|
||||
this.insert = this.insertDefaultForTarget();
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.questionInput && this.$refs.questionInput.focus) {
|
||||
this.$refs.questionInput.focus();
|
||||
|
||||
@@ -15,16 +15,10 @@
|
||||
<v-list-item-subtitle>{{ primaryModifierLabel }}+click to wipe and start fresh</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
|
||||
<!-- add tracked world state -->
|
||||
<v-list-item density="compact" prepend-icon="mdi-cube-scan" @click="$refs.createWorldState.open()">
|
||||
<v-list-item-title>Add tracked world state</v-list-item-title>
|
||||
<v-list-item-subtitle>Track and auto-update a world state</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
|
||||
<!-- add tracked character state -->
|
||||
<v-list-item density="compact" prepend-icon="mdi-account-search" @click="$refs.createCharacterState.open()">
|
||||
<v-list-item-title>Add tracked character state</v-list-item-title>
|
||||
<v-list-item-subtitle>Track and auto-update a character state</v-list-item-subtitle>
|
||||
<!-- track state -->
|
||||
<v-list-item density="compact" prepend-icon="mdi-cube-scan" @click="$refs.trackState.open()">
|
||||
<v-list-item-title>Track state</v-list-item-title>
|
||||
<v-list-item-subtitle>Track and auto-update a world or character state</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
|
||||
<!-- player character submenu -->
|
||||
@@ -121,22 +115,15 @@
|
||||
/>
|
||||
|
||||
<QuickCreateStateReinforcement
|
||||
ref="createWorldState"
|
||||
title="Add Tracked World State"
|
||||
description="Create a tracked world state that the AI will automatically monitor and update at a regular interval. Once created, the state can be found and managed in the World State Manager under the World States tab."
|
||||
:insertion-modes="insertionModes"
|
||||
default-insert="never"
|
||||
@create="createWorldStateReinforcement"
|
||||
/>
|
||||
|
||||
<QuickCreateStateReinforcement
|
||||
ref="createCharacterState"
|
||||
title="Add Tracked Character State"
|
||||
description="Create a tracked character state that the AI will automatically monitor and update at a regular interval. Once created, the state can be found and managed in the World State Manager under the character's Tracked States tab."
|
||||
ref="trackState"
|
||||
title="Track State"
|
||||
description="Create a tracked state that the AI will automatically monitor and update at a regular interval. Choose whether to track a world state or a specific character's state. Once created, it can be found and managed in the World State Manager."
|
||||
:insertion-modes="insertionModes"
|
||||
:characters="allCharacters"
|
||||
default-insert="sequential"
|
||||
@create="createCharacterStateReinforcement"
|
||||
allow-world
|
||||
character-default-insert="sequential"
|
||||
world-default-insert="never"
|
||||
@create="createStateReinforcement"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -384,6 +371,14 @@ export default {
|
||||
}));
|
||||
},
|
||||
|
||||
createStateReinforcement(data) {
|
||||
if (data.character) {
|
||||
this.createCharacterStateReinforcement(data);
|
||||
} else {
|
||||
this.createWorldStateReinforcement(data);
|
||||
}
|
||||
},
|
||||
|
||||
createWorldStateReinforcement(data) {
|
||||
this.getWebsocket().send(JSON.stringify({
|
||||
type: 'world_state_manager',
|
||||
|
||||
Reference in New Issue
Block a user