// ── Agent Page ── let _agentAvatarData = null; let _agentPasteHandler = null; registerPage('agent', { async init(params) { const agentId = params.id; const isNew = !agentId; let agent = null; if (!isNew) { agent = await apiGetAgent(agentId); if (!agent) return navigateTo('dashboard'); } const title = document.getElementById('agentPageTitle'); const nameEl = document.getElementById('agentName'); const descEl = document.getElementById('agentDescription'); const modelEl = document.getElementById('agentModel'); const toolChoiceEl = document.getElementById('agentToolChoice'); const autoCommitEl = document.getElementById('agentAutoCommit'); const useSoulEl = document.getElementById('agentUseSoul'); const useIdentityEl = document.getElementById('agentUseIdentity'); const useUserInfoEl = document.getElementById('agentUseUserInfo'); const useMemoryEl = document.getElementById('agentUseMemory'); const webSearchVersionEl = document.getElementById('agentWebSearchVersion'); const avatarPreview = document.getElementById('avatarPreview'); const avatarInput = document.getElementById('avatarInput'); const avatarBtn = document.getElementById('avatarBtn'); const avatarClearBtn = document.getElementById('avatarClearBtn'); const saveBtn = document.getElementById('agentSaveBtn'); const cancelBtn = document.getElementById('agentCancelBtn'); const deleteBtn = document.getElementById('agentDeleteBtn'); const commandsList = document.getElementById('agentCommandsList'); const addCommandBtn = document.getElementById('agentAddCommandBtn'); const skillsSection = document.getElementById('agentSkillsSection'); const skillList = document.getElementById('agentSkillList'); const more = document.querySelector('.more'); const scaleRow = document.getElementById('agentScaleRow'); const scaleInput = document.getElementById('agentAvatarScale'); const scaleValue = document.getElementById('agentScaleValue'); _agentAvatarData = null; function updatePreviewScale() { var img = avatarPreview.querySelector('img'); if (img) img.style.scale = scaleInput.value; scaleValue.textContent = scaleInput.value + '×'; } scaleInput.addEventListener('input', updatePreviewScale); if (agent) { title.textContent = agent.name; nameEl.value = agent.name || ''; descEl.value = agent.description || ''; modelEl.value = agent.model || 'sonnet'; toolChoiceEl.checked = (agent.toolChoice || 'any') === 'any'; autoCommitEl.value = agent.autoCommit || ''; useSoulEl.checked = agent.useSoul !== false; useIdentityEl.checked = agent.useIdentity !== false; useUserInfoEl.checked = agent.useUserInfo !== false; useMemoryEl.checked = agent.useMemory !== false; webSearchVersionEl.value = agent.webSearchVersion || ''; _agentAvatarData = agent.avatar || null; deleteBtn.hidden = false; if (agent.avatarScale && agent.avatarScale !== 1) { scaleInput.value = agent.avatarScale; scaleValue.textContent = agent.avatarScale + '×'; } if (agent.avatar) { avatarPreview.innerHTML = `Avatar`; scaleRow.hidden = false; } // Custom Commands laden loadCommandsIntoUI(commandsList, agent.customCommands); // Skills laden const [allSkills, agentSkills] = await Promise.all([ apiGetSkills(), apiGetAgentSkills(agentId) ]); const assignedSlugs = agentSkills.map(s => s.slug); skillsSection.hidden = false; renderSkillCheckboxes(skillList, allSkills, assignedSlugs); } else { // Neue Agents: Skills-Liste auch anzeigen const allSkills = await apiGetSkills(); if (allSkills.length > 0) { skillsSection.hidden = false; renderSkillCheckboxes(skillList, allSkills, []); } } // Befehl hinzufügen addCommandBtn.addEventListener('click', () => createCommandRow(commandsList)); // AI Bild-Generierung (nur wenn Krea konfiguriert) const aiSection = document.getElementById('agentAiSection'); const aiPrompt = document.getElementById('agentAiPrompt'); const aiGenerateBtn = document.getElementById('agentAiGenerateBtn'); apiKreaStatus().then(status => { if (status.configured) aiSection.hidden = false; }); aiGenerateBtn.addEventListener('click', async () => { const prompt = aiPrompt.value.trim(); if (!prompt) return; aiGenerateBtn.disabled = true; aiGenerateBtn.innerHTML = ''; try { const result = await apiKreaGenerate(prompt); if (result.files && result.files.length > 0) { const imgResp = await fetch('/api/images/file/' + result.files[0]); const blob = await imgResp.blob(); const reader = new FileReader(); reader.onload = () => { _agentAvatarData = reader.result; avatarPreview.innerHTML = `Avatar`; scaleRow.hidden = false; updatePreviewScale(); }; reader.readAsDataURL(blob); } } catch (e) { showToast('Fehler: ' + e.message, 'error'); } finally { aiGenerateBtn.disabled = false; aiGenerateBtn.innerHTML = ''; } }); aiPrompt.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); aiGenerateBtn.click(); } }); // Avatar Upload avatarBtn.addEventListener('click', () => avatarInput.click()); avatarInput.addEventListener('change', () => { const file = avatarInput.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = () => { _agentAvatarData = reader.result; avatarPreview.innerHTML = `Avatar`; scaleRow.hidden = false; updatePreviewScale(); }; reader.readAsDataURL(file); }); avatarClearBtn.addEventListener('click', () => { _agentAvatarData = null; avatarPreview.innerHTML = '?'; avatarInput.value = ''; scaleRow.hidden = true; scaleInput.value = 1; scaleValue.textContent = '1×'; }); // Avatar Paste (Ctrl+V) document.addEventListener('paste', _agentPasteHandler = (e) => { const items = e.clipboardData?.items; if (!items) return; for (const item of items) { if (item.type.startsWith('image/')) { e.preventDefault(); const file = item.getAsFile(); if (!file) return; const reader = new FileReader(); reader.onload = () => { _agentAvatarData = reader.result; avatarPreview.innerHTML = `Avatar`; scaleRow.hidden = false; updatePreviewScale(); }; reader.readAsDataURL(file); return; } } }); more.addEventListener('click', () => { const content = more.querySelector('[hidden]'); while (content.firstChild) more.parentNode.insertBefore(content.firstChild, more); more.remove(); }); // Speichern saveBtn.addEventListener('click', async () => { const data = { name: nameEl.value.trim() || 'Unbenannt', description: descEl.value.trim(), model: modelEl.value, toolChoice: toolChoiceEl.checked ? 'any' : 'auto', autoCommit: autoCommitEl.value, useSoul: useSoulEl.checked, useIdentity: useIdentityEl.checked, useUserInfo: useUserInfoEl.checked, useMemory: useMemoryEl.checked, webSearchVersion: webSearchVersionEl.value, avatar: _agentAvatarData, avatarScale: parseFloat(scaleInput.value) || 1, customCommands: getCommandsFromUI(commandsList) }; if (isNew) { const created = await apiCreateAgent(data); // Skills zuweisen falls welche ausgewählt const selectedSlugs = getSelectedSkills(skillList); if (selectedSlugs.length > 0) { await apiSetAgentSkills(created.agentId, selectedSlugs); } } else { await apiUpdateAgent(agentId, data); // Skills aktualisieren const selectedSlugs = getSelectedSkills(skillList); await apiSetAgentSkills(agentId, selectedSlugs); } navigateTo('dashboard'); }); // Abbrechen cancelBtn.addEventListener('click', () => navigateTo('dashboard')); // Löschen deleteBtn.addEventListener('click', async () => { if (!confirm('Agent wirklich löschen?')) return; await apiDeleteAgent(agentId); navigateTo('dashboard'); }); }, destroy() { if (_agentPasteHandler) { document.removeEventListener('paste', _agentPasteHandler); _agentPasteHandler = null; } _agentAvatarData = null; } }); function renderSkillCheckboxes(container, allSkills, assignedSlugs) { container.innerHTML = ''; if (allSkills.length === 0) { container.innerHTML = '
Keine Skills verfügbar. Lege Skills in data/skills/ ab.
'; return; } for (const skill of allSkills) { const checked = assignedSlugs.includes(skill.slug) ? 'checked' : ''; const disabled = !skill.hasPromptMd ? 'disabled' : ''; const version = skill.version ? ` v${skill.version}` : ''; const desc = skill.description ? `${skill.description}` : ''; const warning = !skill.hasPromptMd ? '⚠ PROMPT.md fehlt – Skill nicht verwendbar' : ''; const row = document.createElement('label'); row.className = 'skill-item' + (!skill.hasPromptMd ? ' skill-unavailable' : ''); row.innerHTML = ` ${skill.name}${version} ${desc} ${warning} `; container.appendChild(row); } } function getSelectedSkills(container) { return Array.from(container.querySelectorAll('input[type="checkbox"]:checked')) .map(cb => cb.value); }