diff --git a/src/renderer/components/memory-panel.ts b/src/renderer/components/memory-panel.ts index 905b287..007ceb3 100644 --- a/src/renderer/components/memory-panel.ts +++ b/src/renderer/components/memory-panel.ts @@ -1,6 +1,6 @@ /** * MemoryPanel - Agent 记忆管理面板 - * 替代 PresetBar,提供记忆的查看、搜索、编辑、删除功能 + * 提供记忆的查看、搜索、编辑、删除功能 */ import { state, KEYS } from '../state/state.js'; diff --git a/src/renderer/components/preset-bar.ts b/src/renderer/components/preset-bar.ts deleted file mode 100644 index 0fdac69..0000000 --- a/src/renderer/components/preset-bar.ts +++ /dev/null @@ -1,187 +0,0 @@ -/** - * PresetBar - 预设栏组件 - */ - -import { state, KEYS } from '../state/state.js'; -import { - getPresets, getActivePresetId, activatePreset, - createPreset, updatePreset, deletePreset -} from '../services/preset-manager.js'; -import { showToast } from './toast.js'; -import type { Preset } from '../types.js'; - -let presetBarEl: HTMLElement; -let presetListEl: HTMLElement; -let editingPresetId: string | null = null; - -function escapeHtml(str: string): string { - const map: Record = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; - return String(str).replace(/[&<>"']/g, c => map[c]); -} - -export function initPresetBar(): void { - const modelBar = document.querySelector('.model-bar'); - if (!modelBar) return; - - const bar = document.createElement('div'); - bar.className = 'preset-bar'; - bar.innerHTML = ` -
- - `; - modelBar.after(bar); - - presetBarEl = bar; - presetListEl = bar.querySelector('#presetList')!; - - bar.querySelector('#btnAddPreset')!.addEventListener('click', () => openPresetModal()); - - state.on('activePresetId', renderPresetBar); - state.on('presets', renderPresetBar); - - renderPresetBar(); -} - -function renderPresetBar(): void { - if (!presetListEl) return; - - const presets = getPresets(); - const activeId = getActivePresetId(); - - presetListEl.innerHTML = ''; - - for (const preset of presets) { - const chip = document.createElement('button'); - chip.className = 'preset-chip' + (preset.id === activeId ? ' active' : ''); - chip.title = preset.systemPrompt ? preset.systemPrompt.slice(0, 100) : '无系统提示词'; - chip.innerHTML = `${preset.icon}${escapeHtml(preset.name)}`; - - chip.addEventListener('click', () => handlePresetClick(preset.id)); - chip.addEventListener('contextmenu', (e) => { - if (!preset.builtIn) { - e.preventDefault(); - editingPresetId = preset.id; - openPresetModal(preset); - } - }); - - presetListEl.appendChild(chip); - } -} - -async function handlePresetClick(presetId: string): Promise { - const currentId = getActivePresetId(); - if (presetId === currentId) return; - - await activatePreset(presetId); - - const preset = getPresets().find(p => p.id === presetId); - if (preset) { - showToast(`已切换到 ${preset.icon} ${preset.name}`, 'success', 2000); - } -} - -function openPresetModal(editPreset?: Preset): void { - const modal = document.querySelector('#presetModal') as HTMLElement; - const titleEl = modal.querySelector('#presetModalTitle')!; - const nameInput = modal.querySelector('#inputPresetName') as HTMLInputElement; - const iconInput = modal.querySelector('#inputPresetIcon') as HTMLInputElement; - const spInput = modal.querySelector('#inputPresetSystemPrompt') as HTMLTextAreaElement; - const tempInput = modal.querySelector('#inputPresetTemp') as HTMLInputElement; - const tempVal = modal.querySelector('#presetTempValue')!; - const ctxInput = modal.querySelector('#inputPresetNumCtx') as HTMLInputElement; - const thinkCheck = modal.querySelector('#togglePresetThink') as HTMLInputElement; - const btnSave = modal.querySelector('#btnSavePreset') as HTMLButtonElement; - const btnDelete = modal.querySelector('#btnDeletePreset') as HTMLElement; - - if (editPreset && editPreset.id) { - editingPresetId = editPreset.id; - titleEl.textContent = '✏️ 编辑预设'; - nameInput.value = editPreset.name; - iconInput.value = editPreset.icon; - spInput.value = editPreset.systemPrompt; - tempInput.value = String(editPreset.temperature ?? 0.7); - tempVal.textContent = (editPreset.temperature ?? 0.7).toFixed(1); - ctxInput.value = String(editPreset.numCtx || 24576); - thinkCheck.checked = editPreset.think ?? false; - btnDelete.style.display = editPreset.builtIn ? 'none' : ''; - btnSave.textContent = '保存'; - } else { - editingPresetId = null; - titleEl.textContent = '✨ 新建预设'; - nameInput.value = ''; - iconInput.value = '🤖'; - spInput.value = ''; - tempInput.value = '0.7'; - tempVal.textContent = '0.7'; - ctxInput.value = '24576'; - thinkCheck.checked = false; - btnDelete.style.display = 'none'; - btnSave.textContent = '创建'; - } - - modal.style.display = ''; - nameInput.focus(); - - tempInput.oninput = () => { - tempVal.textContent = parseFloat(tempInput.value).toFixed(1); - }; -} - -export function initPresetModal(): void { - const modal = document.querySelector('#presetModal') as HTMLElement; - if (!modal) return; - - modal.querySelector('#btnClosePresetModal')!.addEventListener('click', () => { - modal.style.display = 'none'; - }); - modal.addEventListener('click', (e) => { - if (e.target === modal) modal.style.display = 'none'; - }); - - modal.querySelector('#btnSavePreset')!.addEventListener('click', async () => { - const name = (modal.querySelector('#inputPresetName') as HTMLInputElement).value.trim(); - if (!name) { showToast('请输入预设名称', 'warning'); return; } - - const data = { - name, - icon: (modal.querySelector('#inputPresetIcon') as HTMLInputElement).value.trim() || '🤖', - systemPrompt: (modal.querySelector('#inputPresetSystemPrompt') as HTMLTextAreaElement).value.trim(), - temperature: parseFloat((modal.querySelector('#inputPresetTemp') as HTMLInputElement).value) || 0.7, - numCtx: parseInt((modal.querySelector('#inputPresetNumCtx') as HTMLInputElement).value) || 24576, - think: (modal.querySelector('#togglePresetThink') as HTMLInputElement).checked - }; - - if (editingPresetId) { - await updatePreset(editingPresetId, data); - showToast('预设已更新', 'success', 2000); - if (editingPresetId === getActivePresetId()) { - await activatePreset(editingPresetId); - } - } else { - const created = await createPreset(data); - await activatePreset(created.id); - showToast(`已创建并激活 ${data.icon} ${data.name}`, 'success', 2000); - } - - modal.style.display = 'none'; - editingPresetId = null; - }); - - modal.querySelector('#btnDeletePreset')!.addEventListener('click', async () => { - if (!editingPresetId) return; - const preset = getPresets().find(p => p.id === editingPresetId); - if (!preset) return; - - if (confirm(`确定删除预设 "${preset.icon} ${preset.name}" ?`)) { - await deletePreset(editingPresetId); - showToast('预设已删除', 'info', 2000); - modal.style.display = 'none'; - editingPresetId = null; - } - }); -} diff --git a/src/renderer/components/settings-modal.ts b/src/renderer/components/settings-modal.ts index a4f0d2b..62af777 100644 --- a/src/renderer/components/settings-modal.ts +++ b/src/renderer/components/settings-modal.ts @@ -6,6 +6,7 @@ import { state, KEYS } from '../state/state.js'; import { debounce } from '../utils/utils.js'; import { encryptData, decryptData, isMetonaFile } from '../services/crypto.js'; import { setMemoryEnabled } from '../services/memory-manager.js'; +import { setToolEnabled } from '../services/tool-registry.js'; import { updateConnectionInfo, updateRunningModels } from './header.js'; import { loadModels } from './model-bar.js'; import { showToast } from './toast.js'; @@ -122,6 +123,7 @@ export function initSettingsModal(): void { const db = state.get(KEYS.DB); state.set('runCommandEnabled', toggleRunCommand.checked); if (db) await db.saveSetting('runCommandEnabled', toggleRunCommand.checked); + setToolEnabled('run_command', toggleRunCommand.checked); if (toggleRunCommand.checked) { showToast('⚠️ 命令执行已开启,请谨慎使用', 'warning'); } diff --git a/src/renderer/index.html b/src/renderer/index.html index d89d08b..1a1c8b9 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -190,7 +190,7 @@

常见值:2048 / 4096 / 8192 / 32768。值越大上下文越长,显存占用越高。

- +

低值更精确稳定,高值更有创意多样(0 = 确定性,2 = 最大随机)

@@ -356,57 +356,7 @@
- - +