mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-14 02:42:22 +02:00
Squash Odysseus development history
This commit is contained in:
+165
-33
@@ -8,6 +8,24 @@ let API_BASE = '';
|
||||
let selectedPreset = null;
|
||||
let presets = {};
|
||||
|
||||
export function loadStoredArray(key) {
|
||||
try {
|
||||
const value = JSON.parse(localStorage.getItem(key) || '[]');
|
||||
return Array.isArray(value) ? value : [];
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function loadStoredObject(key) {
|
||||
try {
|
||||
const value = JSON.parse(localStorage.getItem(key) || '{}');
|
||||
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// Built-in prompt templates (moved from cot_prompts.py)
|
||||
export const PROMPT_TEMPLATES = [
|
||||
{
|
||||
@@ -41,7 +59,7 @@ export const PROMPT_TEMPLATES = [
|
||||
temperature: 1.0,
|
||||
isPreset: true,
|
||||
isCharacter: true,
|
||||
prompt: "You are Spark, a playful, quick-witted assistant with bright energy and practical instincts. Keep responses concise, vivid, and helpful. Be warm without being cloying, imaginative without losing the thread, and always center the user's actual goal.\n\nUse a light, lively voice with occasional clever turns of phrase. Do not become formal unless the task calls for it. When the user needs precision, prioritize clarity over performance."
|
||||
prompt: "You are Spark: calm, capable, direct, and human. Explain clearly, avoid fluff, and be warm without being performative. Use light dry humor when it fits, challenge weak assumptions respectfully, and adapt your tone to the task. Be concise for simple questions and thorough when the problem deserves it. Never pretend certainty when unsure."
|
||||
},
|
||||
{
|
||||
id: 'odysseus',
|
||||
@@ -191,12 +209,17 @@ function initNameDropdown() {
|
||||
const tempValue = document.getElementById('temp-value');
|
||||
const tokensInput = document.getElementById('custom-max-tokens');
|
||||
const tokensValue = document.getElementById('tokens-value');
|
||||
const thinkingInput = document.getElementById('custom-thinking-mode');
|
||||
if (nameInput) nameInput.value = '';
|
||||
if (promptInput) promptInput.value = '';
|
||||
if (presets.custom) {
|
||||
presets.custom = { ...presets.custom, persona_memory: '', persona_memory_schema: 'general' };
|
||||
}
|
||||
const nameRow = document.getElementById('char-name-row');
|
||||
if (nameRow) nameRow.style.display = '';
|
||||
if (tempInput) { tempInput.value = 1.0; if (tempValue) tempValue.textContent = '1.0'; tempInput.dispatchEvent(new Event('input')); }
|
||||
if (tokensInput) { tokensInput.value = 8448; if (tokensValue) tokensValue.textContent = 'No limit'; tokensInput.dispatchEvent(new Event('input')); }
|
||||
if (thinkingInput) thinkingInput.value = '';
|
||||
if (delBtn) delBtn.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
@@ -220,7 +243,7 @@ function initNameDropdown() {
|
||||
if (!charName || charName === '__default__') return;
|
||||
const match = userTemplates.find(t => t.name === charName);
|
||||
const isBuiltin = PROMPT_TEMPLATES.some(t => t.name === charName);
|
||||
if (!await window.styledConfirm(`Delete "${charName}"?\n\nThis will remove the character and all its memories.`, { confirmText: 'Delete', danger: true })) return;
|
||||
if (!await window.styledConfirm(`Delete "${charName}"?\n\nThis will remove the persona and all its memories.`, { confirmText: 'Delete', danger: true })) return;
|
||||
try {
|
||||
// Delete saved template if exists
|
||||
if (match) {
|
||||
@@ -228,14 +251,14 @@ function initNameDropdown() {
|
||||
}
|
||||
// Hide built-in preset
|
||||
if (isBuiltin) {
|
||||
const hidden = JSON.parse(localStorage.getItem('odysseus-hidden-presets') || '[]');
|
||||
const hidden = loadStoredArray('odysseus-hidden-presets');
|
||||
if (!hidden.includes(charName)) hidden.push(charName);
|
||||
localStorage.setItem('odysseus-hidden-presets', JSON.stringify(hidden));
|
||||
}
|
||||
// Deactivate if this was the active character
|
||||
if (presets.custom && presets.custom.character_name === charName) {
|
||||
selectedPreset = null;
|
||||
presets.custom = { ...presets.custom, character_name: '', system_prompt: '', enabled: false };
|
||||
presets.custom = { ...presets.custom, character_name: '', system_prompt: '', enabled: false, persona_memory: '', persona_memory_schema: 'general' };
|
||||
const charIndicator = document.getElementById('character-indicator-btn');
|
||||
if (charIndicator) { charIndicator.style.display = 'none'; charIndicator.classList.remove('active'); }
|
||||
const miniBtn = document.getElementById('overflow-preset-btn');
|
||||
@@ -267,6 +290,12 @@ function _tryLoadTemplate(name) {
|
||||
if (tempValue) tempValue.textContent = parseFloat(builtin.temperature).toFixed(1);
|
||||
tempInput.dispatchEvent(new Event('input'));
|
||||
}
|
||||
presets.custom = {
|
||||
...(presets.custom || {}),
|
||||
character_name: builtin.isCharacter && !builtin.noName ? name : '',
|
||||
persona_memory: builtin.persona_memory || '',
|
||||
persona_memory_schema: builtin.persona_memory_schema || 'general',
|
||||
};
|
||||
return;
|
||||
}
|
||||
return;
|
||||
@@ -288,6 +317,12 @@ function _tryLoadTemplate(name) {
|
||||
if (tokensValue) tokensValue.textContent = (v === 0 || v > 8192) ? 'No limit' : v.toLocaleString();
|
||||
tokensInput.dispatchEvent(new Event('input'));
|
||||
}
|
||||
presets.custom = {
|
||||
...(presets.custom || {}),
|
||||
character_name: tmpl.name || name,
|
||||
persona_memory: tmpl.persona_memory || '',
|
||||
persona_memory_schema: tmpl.persona_memory_schema || 'general',
|
||||
};
|
||||
const delBtn = document.getElementById('char-delete-template-btn');
|
||||
if (delBtn) delBtn.style.display = '';
|
||||
}
|
||||
@@ -296,7 +331,7 @@ function _populateCharSelect() {
|
||||
const select = document.getElementById('char-template-select');
|
||||
if (!select) return;
|
||||
const currentVal = select.value;
|
||||
select.innerHTML = '<option value="__default__">Default (no character)</option>';
|
||||
select.innerHTML = '<option value="__default__">Default (no persona)</option>';
|
||||
|
||||
const savedNames = new Set(userTemplates.map(t => t.name));
|
||||
if (userTemplates.length) {
|
||||
@@ -311,7 +346,7 @@ function _populateCharSelect() {
|
||||
select.appendChild(group);
|
||||
}
|
||||
|
||||
const hiddenPresets = JSON.parse(localStorage.getItem('odysseus-hidden-presets') || '[]');
|
||||
const hiddenPresets = loadStoredArray('odysseus-hidden-presets');
|
||||
const builtins = PROMPT_TEMPLATES.filter(t => !savedNames.has(t.name) && !hiddenPresets.includes(t.name));
|
||||
if (builtins.length) {
|
||||
const group = document.createElement('optgroup');
|
||||
@@ -405,7 +440,7 @@ function initPersistentChat() {
|
||||
await fetch(`${API_BASE}/api/session/${sessionId}/important`, { method: 'POST', body: favFd });
|
||||
|
||||
// Save session → character mapping so it restores on switch
|
||||
const charSessions = JSON.parse(localStorage.getItem('odysseus-char-sessions') || '{}');
|
||||
const charSessions = loadStoredObject('odysseus-char-sessions');
|
||||
charSessions[sessionId] = charName;
|
||||
localStorage.setItem('odysseus-char-sessions', JSON.stringify(charSessions));
|
||||
|
||||
@@ -437,7 +472,7 @@ function initSaveAsTemplate() {
|
||||
|
||||
let name = nameInput ? nameInput.value.trim() : '';
|
||||
if (!name) {
|
||||
name = prompt('Enter a name for this character:');
|
||||
name = prompt('Enter a name for this persona:');
|
||||
if (!name || !name.trim()) return;
|
||||
name = name.trim();
|
||||
if (nameInput) nameInput.value = name;
|
||||
@@ -450,6 +485,8 @@ function initSaveAsTemplate() {
|
||||
system_prompt: promptInput ? promptInput.value : '',
|
||||
temperature: tempInput ? parseFloat(tempInput.value) : 1.0,
|
||||
max_tokens: _rawTk > 8192 ? 0 : _rawTk,
|
||||
persona_memory: presets.custom?.persona_memory || '',
|
||||
persona_memory_schema: presets.custom?.persona_memory_schema || 'general',
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -486,6 +523,7 @@ export async function loadPresets(showError) {
|
||||
presets = await res.json();
|
||||
|
||||
const custom = presets.custom;
|
||||
if (custom) custom.thinking_mode = ['on', 'off'].includes(custom.thinking_mode) ? custom.thinking_mode : '';
|
||||
if (custom && custom.enabled === undefined) {
|
||||
const legacyPrompt = "You are a helpful, balanced assistant. Match your response style to the user's needs.";
|
||||
if (
|
||||
@@ -503,7 +541,11 @@ export async function loadPresets(showError) {
|
||||
}
|
||||
|
||||
// Auto-activate custom preset if enabled and has content
|
||||
if (custom && custom.enabled !== false && (custom.character_name || custom.system_prompt)) {
|
||||
const hasCustomSettings = custom && (
|
||||
custom.character_name || custom.system_prompt || custom.inject_prefix || custom.inject_suffix
|
||||
|| custom.thinking_mode || custom.temperature !== 1.0 || !!custom.max_tokens
|
||||
);
|
||||
if (custom && custom.enabled !== false && hasCustomSettings) {
|
||||
selectedPreset = 'custom';
|
||||
const miniBtn = document.getElementById('overflow-preset-btn');
|
||||
if (miniBtn) miniBtn.classList.add('active');
|
||||
@@ -539,7 +581,7 @@ export function setActivePreset(presetId) {
|
||||
/**
|
||||
* Open custom preset modal
|
||||
*/
|
||||
export function openCustomPresetModal() {
|
||||
export function openCustomPresetModal(openTab = '') {
|
||||
const modal = document.getElementById('custom-preset-modal');
|
||||
if (!modal) return;
|
||||
|
||||
@@ -547,13 +589,16 @@ export function openCustomPresetModal() {
|
||||
character_name: "",
|
||||
temperature: 1.0,
|
||||
max_tokens: 0,
|
||||
system_prompt: ""
|
||||
system_prompt: "",
|
||||
thinking_mode: ""
|
||||
};
|
||||
|
||||
const nameInput = document.getElementById('custom-character-name');
|
||||
const tempInput = document.getElementById('custom-temperature');
|
||||
const tokensInput = document.getElementById('custom-max-tokens');
|
||||
const promptInput = document.getElementById('custom-system-prompt');
|
||||
const thinkingInput = document.getElementById('custom-thinking-mode');
|
||||
const showNameInput = document.getElementById('custom-show-persona-name');
|
||||
|
||||
if (nameInput) nameInput.value = savedConfig.character_name || '';
|
||||
// Sync select dropdown to current character
|
||||
@@ -580,6 +625,8 @@ export function openCustomPresetModal() {
|
||||
if (tkv) tkv.textContent = (saved === 0 || saved > 8192) ? 'No limit' : parseInt(saved).toLocaleString();
|
||||
}
|
||||
if (promptInput) promptInput.value = savedConfig.system_prompt || '';
|
||||
if (thinkingInput) thinkingInput.value = ['on', 'off'].includes(savedConfig.thinking_mode) ? savedConfig.thinking_mode : '';
|
||||
if (showNameInput) showNameInput.checked = savedConfig.show_persona_name !== false;
|
||||
|
||||
// Load inject fields
|
||||
const prefixInput = document.getElementById('inject-prefix');
|
||||
@@ -593,6 +640,8 @@ export function openCustomPresetModal() {
|
||||
prompt: promptInput ? promptInput.value : '',
|
||||
temp: tempInput ? tempInput.value : '1',
|
||||
tokens: tokensInput ? tokensInput.value : '8448',
|
||||
thinking: thinkingInput ? thinkingInput.value : '',
|
||||
showName: showNameInput ? showNameInput.checked : true,
|
||||
};
|
||||
function _updateStartBtn() {
|
||||
const btn = document.getElementById('save-custom-preset');
|
||||
@@ -601,7 +650,10 @@ export function openCustomPresetModal() {
|
||||
const changed = (nameInput && nameInput.value !== _snapshot.name)
|
||||
|| (promptInput && promptInput.value !== _snapshot.prompt)
|
||||
|| (tempInput && tempInput.value !== _snapshot.temp)
|
||||
|| (tokensInput && tokensInput.value !== _snapshot.tokens);
|
||||
|| (tokensInput && tokensInput.value !== _snapshot.tokens)
|
||||
|| (thinkingInput && thinkingInput.value !== _snapshot.thinking);
|
||||
const nameVisibilityChanged = showNameInput && showNameInput.checked !== _snapshot.showName;
|
||||
const changedWithVisibility = changed || nameVisibilityChanged;
|
||||
// The footer button starts whichever of the three things the active tab
|
||||
// represents — a character chat, a group, or a plain tuned chat. Label
|
||||
// it so the action is obvious instead of a generic "Start".
|
||||
@@ -616,7 +668,7 @@ export function openCustomPresetModal() {
|
||||
} else {
|
||||
// Character/persona tab. "Save & " prefix when the user edited a template,
|
||||
// so it's clear the edit is being saved on start.
|
||||
label = changed ? 'Save & Start Character' : 'Start Character';
|
||||
label = changedWithVisibility ? 'Save & Start Persona' : 'Start Persona';
|
||||
}
|
||||
btn.textContent = label;
|
||||
// Show a "Cancel" button next to Start when the active tab's feature is
|
||||
@@ -630,9 +682,9 @@ export function openCustomPresetModal() {
|
||||
cancelBtn.textContent = activeTab === 'group' ? 'Cancel group' : 'Cancel';
|
||||
}
|
||||
// Reset only makes sense on the character tab (it resets the persona).
|
||||
if (resetBtn) resetBtn.style.display = (changed && activeTab === 'character') ? '' : 'none';
|
||||
if (resetBtn) resetBtn.style.display = (changedWithVisibility && activeTab === 'character') ? '' : 'none';
|
||||
}
|
||||
[nameInput, promptInput, tempInput, tokensInput].forEach(el => {
|
||||
[nameInput, promptInput, tempInput, tokensInput, thinkingInput, showNameInput].forEach(el => {
|
||||
if (el) el.addEventListener('input', _updateStartBtn);
|
||||
});
|
||||
// Re-label the Start button when the user switches tabs. Rebind the fresh
|
||||
@@ -671,6 +723,8 @@ export function openCustomPresetModal() {
|
||||
_snapshot.prompt = promptInput ? promptInput.value : '';
|
||||
_snapshot.temp = tempInput ? tempInput.value : '1';
|
||||
_snapshot.tokens = tokensInput ? tokensInput.value : '8448';
|
||||
_snapshot.thinking = thinkingInput ? thinkingInput.value : '';
|
||||
_snapshot.showName = showNameInput ? showNameInput.checked : true;
|
||||
_updateStartBtn();
|
||||
}, 50));
|
||||
_updateStartBtn();
|
||||
@@ -708,7 +762,7 @@ export function openCustomPresetModal() {
|
||||
const notice = document.createElement('div');
|
||||
notice.id = 'char-lock-notice';
|
||||
notice.style.cssText = 'font-size:11px;color:var(--color-muted);text-align:center;padding:6px;margin-bottom:8px;border:1px dashed var(--border);border-radius:6px;';
|
||||
notice.textContent = 'Persistent chat — character is locked. Style, temperature, and memory can still be changed.';
|
||||
notice.textContent = 'Persistent chat — persona is locked. Style, temperature, and memory can still be changed.';
|
||||
modal.querySelector('.modal-body').prepend(notice);
|
||||
}
|
||||
} else {
|
||||
@@ -720,6 +774,10 @@ export function openCustomPresetModal() {
|
||||
}
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
if (openTab) {
|
||||
const tab = document.querySelector(`.preset-tab[data-chartab="${openTab}"]`);
|
||||
if (tab) tab.click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -730,6 +788,8 @@ export async function saveCustomPreset(showToast, showError) {
|
||||
const tempInput = document.getElementById('custom-temperature');
|
||||
const tokensInput = document.getElementById('custom-max-tokens');
|
||||
const promptInput = document.getElementById('custom-system-prompt');
|
||||
const thinkingInput = document.getElementById('custom-thinking-mode');
|
||||
const showNameInput = document.getElementById('custom-show-persona-name');
|
||||
|
||||
if (!tempInput || !tokensInput || !promptInput) return;
|
||||
|
||||
@@ -770,6 +830,10 @@ export async function saveCustomPreset(showToast, showError) {
|
||||
system_prompt: system_prompt,
|
||||
inject_prefix: _prefixInput ? _prefixInput.value : '',
|
||||
inject_suffix: _suffixInput ? _suffixInput.value : '',
|
||||
thinking_mode: ['on', 'off'].includes(thinkingInput?.value) ? thinkingInput.value : '',
|
||||
show_persona_name: showNameInput ? showNameInput.checked : true,
|
||||
persona_memory: presets.custom?.character_name === name ? (presets.custom?.persona_memory || '') : '',
|
||||
persona_memory_schema: presets.custom?.character_name === name ? (presets.custom?.persona_memory_schema || 'general') : 'general',
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -789,7 +853,7 @@ export async function saveCustomPreset(showToast, showError) {
|
||||
// user has dialed in non-default tuning (temperature / max tokens) — the
|
||||
// "Inject" tab's plain-chat case. Without the tuning check, "just set
|
||||
// temp + max tokens" would silently do nothing.
|
||||
const _hasTuning = (config.temperature !== 1.0) || (config.max_tokens !== 0);
|
||||
const _hasTuning = (config.temperature !== 1.0) || (config.max_tokens !== 0) || !!config.thinking_mode;
|
||||
const _hasInject = !!(config.inject_prefix || config.inject_suffix);
|
||||
const _hasContent = !!(system_prompt || name || _hasTuning || _hasInject);
|
||||
if (enabled && _hasContent) {
|
||||
@@ -812,20 +876,55 @@ export async function saveCustomPreset(showToast, showError) {
|
||||
const _selVal = document.getElementById('char-template-select')?.value || '';
|
||||
const isBuiltinPreset = PROMPT_TEMPLATES.some(t => t.isPreset && (t.name === name || t.name === _selVal));
|
||||
const saveName = isBuiltinPreset ? null : (name || null);
|
||||
|
||||
if (saveName) {
|
||||
fetch(`${API_BASE}/api/presets/templates`, {
|
||||
method: 'POST',
|
||||
const _existing = userTemplates.find(t => t.name === saveName);
|
||||
let clone;
|
||||
const _entry = {
|
||||
id: _existing && _existing.id
|
||||
|| 'user-' + Math.random().toString(16).slice(2, 10),
|
||||
name: saveName,
|
||||
// use ?? since it's more semantic for null-coalescing
|
||||
system_prompt: system_prompt ?? '',
|
||||
temperature: config.temperature,
|
||||
max_tokens: config.max_tokens,
|
||||
persona_memory: config.persona_memory || '',
|
||||
persona_memory_schema: config.persona_memory_schema || 'general',
|
||||
}
|
||||
const ENDPOINT = `${API_BASE}/api/presets/templates`;
|
||||
|
||||
// Optimistically update the in-memory templates list by @michaelxer
|
||||
if (_existing) {
|
||||
// slow but works for now
|
||||
clone = JSON.parse(JSON.stringify(_existing));
|
||||
|
||||
Object.assign(_existing, _entry);
|
||||
} else {
|
||||
userTemplates.push(_entry);
|
||||
}
|
||||
|
||||
fetch(ENDPOINT, {
|
||||
method: "POST",
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
id: (userTemplates.find(t => t.name === saveName) || {}).id || '',
|
||||
name: saveName, system_prompt, temperature: config.temperature, max_tokens: config.max_tokens,
|
||||
}),
|
||||
}).then(r => { if (r.ok) loadUserTemplates(); }).catch(() => {});
|
||||
body: JSON.stringify(_entry)
|
||||
}).then((r) => {
|
||||
if (r.ok) {
|
||||
loadUserTemplates();
|
||||
}
|
||||
}).catch(() => {
|
||||
if (clone) {
|
||||
Object.assign(_existing, clone);
|
||||
}
|
||||
|
||||
if (showError) {
|
||||
showError(_isInjectStart ? "Something went wrong. Saved prompt has been undone." : "Something went wrong. Saved persona has been undone.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (showToast) {
|
||||
// The Inject tab is a plain tuned "prompt" chat, not a persona — say so.
|
||||
showToast(_isInjectStart ? 'Prompt saved' : 'Character saved');
|
||||
showToast(_isInjectStart ? 'Prompt saved' : 'Persona saved');
|
||||
}
|
||||
const modal = document.getElementById('custom-preset-modal');
|
||||
if (modal) {
|
||||
@@ -865,6 +964,13 @@ export function getAllPresets() {
|
||||
return presets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the in-memory user templates list (may be stale; call loadUserTemplates first if freshness matters).
|
||||
*/
|
||||
export function getUserTemplates() {
|
||||
return [...userTemplates];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the character name (if set)
|
||||
*/
|
||||
@@ -875,6 +981,13 @@ export function getCharacterName() {
|
||||
return custom.character_name || '';
|
||||
}
|
||||
|
||||
/** Whether the active persona should be named in the chat UI. */
|
||||
export function getShowPersonaName() {
|
||||
if (!selectedPreset) return true;
|
||||
const custom = presets.custom;
|
||||
return custom?.show_persona_name !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inject prefix/suffix (if set and preset active)
|
||||
*/
|
||||
@@ -892,6 +1005,13 @@ export function getInject() {
|
||||
};
|
||||
}
|
||||
|
||||
export function getThinkingMode() {
|
||||
if (!selectedPreset) return '';
|
||||
const custom = presets.custom;
|
||||
if (!custom || custom.enabled === false) return '';
|
||||
return ['on', 'off'].includes(custom.thinking_mode) ? custom.thinking_mode : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully deactivate the character — clear preset, hide indicator, update overflow btn.
|
||||
*/
|
||||
@@ -950,7 +1070,7 @@ function _syncCharIndicator() {
|
||||
// "Inject mode": custom preset is active for plain tuning / inject only —
|
||||
// no persona. Detected from the custom config so it survives a reload.
|
||||
const _t = parseFloat(custom?.temperature);
|
||||
const _hasTuning = (!isNaN(_t) && _t !== 1.0) || (!!custom?.max_tokens && custom.max_tokens !== 0);
|
||||
const _hasTuning = (!isNaN(_t) && _t !== 1.0) || (!!custom?.max_tokens && custom.max_tokens !== 0) || !!custom?.thinking_mode;
|
||||
const _hasInject = !!(custom?.inject_prefix || custom?.inject_suffix);
|
||||
const injectActive = enabled && !custom?.character_name && (_hasTuning || _hasInject);
|
||||
// Icon path sets for the indicator chip.
|
||||
@@ -961,13 +1081,20 @@ function _syncCharIndicator() {
|
||||
btn.classList.add('active');
|
||||
if (hasChar) {
|
||||
if (iconEl) iconEl.innerHTML = _AVATAR;
|
||||
if (nameSpan) nameSpan.textContent = custom.character_name;
|
||||
btn.title = `Character: ${custom.character_name} — click to configure`;
|
||||
const showName = custom.show_persona_name !== false;
|
||||
if (nameSpan) {
|
||||
nameSpan.textContent = showName ? custom.character_name : '';
|
||||
nameSpan.style.display = showName ? '' : 'none';
|
||||
}
|
||||
btn.title = `Persona: ${custom.character_name} — click to configure`;
|
||||
} else {
|
||||
// Inject/tuning chat — syringe tag labeled "Prompt" to match the
|
||||
// window identity, no persona name.
|
||||
if (iconEl) iconEl.innerHTML = _SYRINGE;
|
||||
if (nameSpan) nameSpan.textContent = 'Prompt';
|
||||
if (nameSpan) {
|
||||
nameSpan.textContent = 'Prompt';
|
||||
nameSpan.style.display = '';
|
||||
}
|
||||
btn.title = 'Custom settings active — click to configure';
|
||||
}
|
||||
// Hide X in persistent chats
|
||||
@@ -993,7 +1120,7 @@ function _syncCharIndicator() {
|
||||
}).catch(() => {});
|
||||
return;
|
||||
}
|
||||
if (typeof openCustomPresetModal === 'function') openCustomPresetModal();
|
||||
if (typeof openCustomPresetModal === 'function') openCustomPresetModal(hasChar ? 'character' : 'inject');
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -1011,7 +1138,7 @@ function _syncCharIndicator() {
|
||||
let _prevSessionId = null;
|
||||
|
||||
export function onSessionSwitch(sessionId) {
|
||||
const charSessions = JSON.parse(localStorage.getItem('odysseus-char-sessions') || '{}');
|
||||
const charSessions = loadStoredObject('odysseus-char-sessions');
|
||||
|
||||
// Leaving a persistent chat — deactivate for this switch only
|
||||
if (window._persistentChatSession) {
|
||||
@@ -1036,6 +1163,8 @@ export function onSessionSwitch(sessionId) {
|
||||
system_prompt: tmpl.system_prompt || tmpl.prompt || '',
|
||||
temperature: tmpl.temperature ?? 1.0,
|
||||
max_tokens: tmpl.max_tokens || 0,
|
||||
persona_memory: tmpl.persona_memory || '',
|
||||
persona_memory_schema: tmpl.persona_memory_schema || 'general',
|
||||
enabled: true,
|
||||
};
|
||||
selectedPreset = 'custom';
|
||||
@@ -1059,7 +1188,7 @@ export function isPersistentChat() {
|
||||
* Remove a session from persistent chat mappings (call when session is deleted).
|
||||
*/
|
||||
export function removePersistentChat(sessionId) {
|
||||
const charSessions = JSON.parse(localStorage.getItem('odysseus-char-sessions') || '{}');
|
||||
const charSessions = loadStoredObject('odysseus-char-sessions');
|
||||
if (charSessions[sessionId]) {
|
||||
delete charSessions[sessionId];
|
||||
localStorage.setItem('odysseus-char-sessions', JSON.stringify(charSessions));
|
||||
@@ -1081,12 +1210,15 @@ const presetsModule = {
|
||||
getSelectedPreset,
|
||||
getPreset,
|
||||
getAllPresets,
|
||||
getUserTemplates,
|
||||
getCharacterName,
|
||||
getShowPersonaName,
|
||||
onSessionSwitch,
|
||||
isPersistentChat,
|
||||
removePersistentChat,
|
||||
deactivateCharacter,
|
||||
getInject
|
||||
getInject,
|
||||
getThinkingMode
|
||||
};
|
||||
|
||||
export default presetsModule;
|
||||
|
||||
Reference in New Issue
Block a user