Changeset 0.9.3 (#53)
This commit is contained in:
@@ -25,7 +25,7 @@ const App = {
|
||||
settings: {
|
||||
model: '',
|
||||
stream: true,
|
||||
showThinking: true,
|
||||
showThinking: false,
|
||||
systemPrompt: '',
|
||||
maxTokens: 0, // 0 = auto from model capabilities
|
||||
temperature: 0.7,
|
||||
@@ -287,6 +287,7 @@ function resolveCapabilities(backendCaps, modelId) {
|
||||
async function fetchModels() {
|
||||
try {
|
||||
const data = await API.listEnabledModels();
|
||||
App.defaultModel = data.default_model || '';
|
||||
// Load user model preferences
|
||||
try {
|
||||
const prefData = await API.getModelPreferences();
|
||||
@@ -335,6 +336,7 @@ async function fetchModels() {
|
||||
});
|
||||
console.log(`📋 Loaded ${App.models.length} models (${App.models.filter(m => m.isPreset).length} presets, ${App.models.filter(m => m.hidden).length} hidden)`);
|
||||
} catch (e) { console.warn('Model fetch failed:', e.message); }
|
||||
|
||||
UI.updateModelSelector();
|
||||
UI.updateCapabilityBadges();
|
||||
}
|
||||
@@ -382,6 +384,7 @@ async function selectChat(chatId) {
|
||||
model: m.model || '',
|
||||
modelName: '',
|
||||
timestamp: m.created_at,
|
||||
tool_calls: m.tool_calls || null,
|
||||
siblingCount: m.sibling_count || 1,
|
||||
siblingIndex: m.sibling_index || 0,
|
||||
}));
|
||||
@@ -514,6 +517,7 @@ async function reloadActivePath() {
|
||||
model: m.model || '',
|
||||
modelName: '',
|
||||
timestamp: m.created_at,
|
||||
tool_calls: m.tool_calls || null,
|
||||
siblingCount: m.sibling_count || 1,
|
||||
siblingIndex: m.sibling_index || 0,
|
||||
}));
|
||||
@@ -535,12 +539,23 @@ async function regenerateMessage(messageId) {
|
||||
const model = modelInfo?.baseModelId || selectedId;
|
||||
const presetId = modelInfo?.isPreset ? modelInfo.presetId : null;
|
||||
|
||||
// Truncate display to the parent of the message being regenerated.
|
||||
// This makes the stream appear in the correct position — as a fresh
|
||||
// response to the parent user message, not appended at the bottom.
|
||||
const chat = App.chats.find(c => c.id === App.currentChatId);
|
||||
if (chat) {
|
||||
const msgIdx = chat.messages.findIndex(m => m.id === messageId);
|
||||
if (msgIdx > 0) {
|
||||
const truncated = chat.messages.slice(0, msgIdx);
|
||||
UI.renderMessages(truncated);
|
||||
}
|
||||
}
|
||||
|
||||
App.isGenerating = true;
|
||||
App.abortController = new AbortController();
|
||||
UI.setGenerating(true);
|
||||
|
||||
try {
|
||||
const chat = App.chats.find(c => c.id === App.currentChatId);
|
||||
const resp = await API.streamRegenerate(
|
||||
App.currentChatId, messageId, App.abortController.signal,
|
||||
model, presetId, modelInfo?.configId
|
||||
@@ -969,7 +984,8 @@ function initListeners() {
|
||||
});
|
||||
document.getElementById('fetchModelsBtn')?.addEventListener('click', async () => {
|
||||
await fetchModels();
|
||||
UI.toast(`Loaded ${App.models.length} models`, 'success');
|
||||
const visible = App.models.filter(m => !m.hidden).length;
|
||||
UI.toast(`Loaded ${visible} model${visible !== 1 ? 's' : ''}`, 'success');
|
||||
});
|
||||
|
||||
// Settings modal
|
||||
@@ -1385,12 +1401,15 @@ function initListeners() {
|
||||
|
||||
// Keyboard shortcuts
|
||||
document.addEventListener('keydown', (e) => {
|
||||
// Escape: stop generation → close command palette → close topmost modal
|
||||
// Escape: stop generation → close command palette → close side panel → close topmost modal
|
||||
if (e.key === 'Escape') {
|
||||
if (App.isGenerating) { stopGeneration(); return; }
|
||||
if (document.getElementById('cmdPalette')?.classList.contains('active')) {
|
||||
closeCmdPalette(); return;
|
||||
}
|
||||
if (document.getElementById('sidePanel')?.classList.contains('open')) {
|
||||
closeSidePanel(); return;
|
||||
}
|
||||
const open = [...document.querySelectorAll('.modal-overlay.active')];
|
||||
if (open.length) closeModal(open[open.length - 1].id);
|
||||
return;
|
||||
@@ -1690,6 +1709,10 @@ async function handleSaveAdminSettings() {
|
||||
const userPresets = document.getElementById('adminUserPresetsToggle').checked;
|
||||
await API.adminUpdateSetting('allow_user_personas', { value: userPresets ? 'true' : 'false' });
|
||||
|
||||
// Default model → default_model policy
|
||||
const defaultModel = document.getElementById('adminDefaultModel').value;
|
||||
await API.adminUpdateSetting('default_model', { value: defaultModel });
|
||||
|
||||
// Banner → global_settings (JSON value)
|
||||
const banner = {
|
||||
enabled: document.getElementById('adminBannerEnabled').checked,
|
||||
@@ -2177,7 +2200,7 @@ var _selectedNoteIds = new Set();
|
||||
var _notesSort = 'updated_desc';
|
||||
|
||||
async function openNotes() {
|
||||
openModal('notesModal');
|
||||
openSidePanel('notes');
|
||||
_exitSelectMode();
|
||||
await loadNotesList();
|
||||
await loadNoteFolders();
|
||||
@@ -2336,6 +2359,12 @@ function showNotesList() {
|
||||
|
||||
var _currentNote = null; // cached note for read mode
|
||||
|
||||
function copyNoteContent() {
|
||||
if (!_currentNote) return;
|
||||
const text = `# ${_currentNote.title || ''}\n\n${_currentNote.content || ''}`;
|
||||
navigator.clipboard.writeText(text).then(() => UI.toast('Copied', 'success'));
|
||||
}
|
||||
|
||||
async function openNoteEditor(noteId) {
|
||||
document.getElementById('notesListView').style.display = 'none';
|
||||
document.getElementById('notesEditorView').style.display = '';
|
||||
|
||||
Reference in New Issue
Block a user