Web-Suche (Agent-Toggle mit Versionswahl), Admin-only Backup, Haiku 4.5
- Agent: Web-Suche als Dropdown (Deaktiviert / 2025 / 2026) statt bool - AnthropicService: web_search Tool dynamisch nach Version einfügen - Stream: server_tool_use + web_search_tool_result Events verarbeiten - Chat-Frontend: web_search_start/end Events mit Suchindikator - Dashboard: Badge zeigt Web-Suche mit Jahresversion - UserRecord: IsAdmin Feld, DB-Migration is_admin Spalte - AuthMiddleware: IsAdmin aus DB laden und in Context setzen - BackupEndpoint: Admin-Check (403 für Nicht-Admins) - AuthEndpoint: isAdmin in Login/Me Response - Frontend: Backup-Section nur für Admins sichtbar - Haiku 4.5 als Model-Option (Agent-Dropdown + ChatEndpoint) - TODO: Cronjobs, Haiku ergänzt
This commit is contained in:
1 parent
485f47b29a
commit
8039b47dec
19 files changed
+155
-20
No files matched your search
+8
-1
@@ -134,6 +134,7 @@
|
||||
<select id="agentModel">
|
||||
<option value="sonnet">Sonnet 4.6</option>
|
||||
<option value="opus">Opus 4.6</option>
|
||||
<option value="haiku">Haiku 4.5</option>
|
||||
</select>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="agentToolChoice" checked>
|
||||
@@ -163,6 +164,12 @@
|
||||
<input type="checkbox" id="agentUseMemory" checked>
|
||||
Zugriff auf Erinnerungen <span class="checkbox-hint">(Memory-Tools verfügbar)</span>
|
||||
</label>
|
||||
<label>Web-Suche</label>
|
||||
<select id="agentWebSearchVersion">
|
||||
<option value="">Deaktiviert</option>
|
||||
<option value="web_search_20250305">Aktiviert (2025)</option>
|
||||
<option value="web_search_20260209">Aktiviert (2026)</option>
|
||||
</select>
|
||||
<label>Skills</label>
|
||||
<div id="agentSkillsSection" hidden>
|
||||
<div class="skill-list" id="agentSkillList"></div>
|
||||
@@ -261,7 +268,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="settings-section">
|
||||
<section id="settingsBackupSection" class="settings-section" style="display:none">
|
||||
<h2>Daten</h2>
|
||||
<div class="setting-row">
|
||||
<div class="setting-info">
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// ── Global User State ──
|
||||
var currentUser = null;
|
||||
|
||||
// ── App Init ──
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
@@ -8,6 +11,8 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
currentUser = user;
|
||||
|
||||
const { page, id } = parseHash();
|
||||
var target = page === 'login' ? 'dashboard' : page;
|
||||
await navigateTo(target, { id }, { replace: true });
|
||||
|
||||
@@ -184,6 +184,18 @@ async function sendMessage() {
|
||||
currentToolBox = null;
|
||||
break;
|
||||
|
||||
case 'web_search_start':
|
||||
endStreamBubble();
|
||||
currentToolBox = addToolBoxLoading('web_search');
|
||||
break;
|
||||
|
||||
case 'web_search_end':
|
||||
if (currentToolBox) {
|
||||
finishToolBox(currentToolBox, { name: 'web_search', result: 'Suche abgeschlossen', isError: false });
|
||||
}
|
||||
currentToolBox = null;
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
endStreamBubble();
|
||||
addErrorBubble(data.error, true);
|
||||
|
||||
@@ -24,6 +24,7 @@ registerPage('agent', {
|
||||
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');
|
||||
@@ -49,6 +50,7 @@ registerPage('agent', {
|
||||
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;
|
||||
|
||||
@@ -130,6 +132,7 @@ registerPage('agent', {
|
||||
useIdentity: useIdentityEl.checked,
|
||||
useUserInfo: useUserInfoEl.checked,
|
||||
useMemory: useMemoryEl.checked,
|
||||
webSearchVersion: webSearchVersionEl.value,
|
||||
avatar: _agentAvatarData,
|
||||
customCommands: getCommandsFromUI(commandsList)
|
||||
};
|
||||
|
||||
@@ -152,6 +152,10 @@ registerPage('dashboard', {
|
||||
if (a.useIdentity) badges.push('<span class="badge badge-feature" title="Hat eine Identität (IDENTITY.md)"><i class="fa fa-id-badge"></i> Ich</span>');
|
||||
if (a.useUserInfo) badges.push('<span class="badge badge-feature" title="Kennt sein Gegenüber (USER.md)"><i class="fa fa-user"></i> Du</span>');
|
||||
if (a.useMemory) badges.push('<span class="badge badge-feature" title="Auf Erinnerungen zugreifen (Memory-Tools)"><i class="fa fa-database"></i> Erinnerungen</span>');
|
||||
if (a.webSearchVersion) {
|
||||
const wsYear = a.webSearchVersion.includes('2025') ? '2025' : '2026';
|
||||
badges.push(`<span class="badge badge-feature" title="Web-Suche (${wsYear})"><i class="fa fa-search"></i> Web-Suche</span>`);
|
||||
}
|
||||
|
||||
const skills = agentSkillsMap[a.agentId] || [];
|
||||
for (const skill of skills) {
|
||||
|
||||
@@ -22,7 +22,7 @@ registerPage('login', {
|
||||
return;
|
||||
}
|
||||
|
||||
await apiLogin(username, password);
|
||||
currentUser = await apiLogin(username, password);
|
||||
navigateTo('dashboard');
|
||||
} catch (err) {
|
||||
errorDiv.textContent = err.message || 'Login fehlgeschlagen';
|
||||
|
||||
@@ -39,6 +39,12 @@ registerPage('settings', {
|
||||
const toolCallSelect = document.getElementById('settingToolCallDisplay');
|
||||
const chainMetaSelect = document.getElementById('settingChainMetaDisplay');
|
||||
const resetBtn = document.getElementById('settingsResetBtn');
|
||||
const backupSection = document.getElementById('settingsBackupSection');
|
||||
|
||||
// Backup nur für Admins
|
||||
if (currentUser && currentUser.isAdmin) {
|
||||
backupSection.style.display = '';
|
||||
}
|
||||
|
||||
const s = loadSettings();
|
||||
slider.value = s.pageWidth;
|
||||
|
||||
+13
-4
@@ -14,8 +14,9 @@ function prettyModelName(model) {
|
||||
if (minor && minor.length <= 2) return family + ' ' + major + '.' + minor;
|
||||
return family + ' ' + major;
|
||||
}
|
||||
if (model == 'sonnet') return 'Sonnet'
|
||||
if (model == 'opus') return 'Opus'
|
||||
if (model == 'sonnet') return 'Sonnet 4.6'
|
||||
if (model == 'opus') return 'Opus 4.6'
|
||||
if (model == 'haiku') return 'Haiku 4.5'
|
||||
return 'Unbekannt (' + model + ')';
|
||||
}
|
||||
|
||||
@@ -333,6 +334,13 @@ function endStreamBubble() {
|
||||
// ── Tool Call Visibility ──
|
||||
|
||||
const MODIFICATION_TOOLS = ['write_file', 'edit_file', 'delete_file', 'memory_write'];
|
||||
const TOOL_DISPLAY_NAMES = {
|
||||
write_file: 'Datei schreiben',
|
||||
edit_file: 'Datei bearbeiten',
|
||||
delete_file: 'Datei löschen',
|
||||
memory_write: 'Erinnerungen festhalten',
|
||||
web_search: 'Web-Suche'
|
||||
};
|
||||
|
||||
function isToolVisible(toolName) {
|
||||
const mode = loadSettings().toolCallDisplay;
|
||||
@@ -362,7 +370,8 @@ function isChainMetaVisible(chainData) {
|
||||
function addToolBoxLoading(name) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'tool-box streamed';
|
||||
div.innerHTML = '<span class="tool-name">' + esc(name) + '</span> <span class="tool-spinner"><i class="fa fa-hourglass-half"></i></span>';
|
||||
const displayName = TOOL_DISPLAY_NAMES[name] || name;
|
||||
div.innerHTML = '<span class="tool-name">' + esc(displayName) + '</span> <span class="tool-spinner"><i class="fa fa-hourglass-half"></i></span>';
|
||||
chatEl().appendChild(div);
|
||||
scrollDown();
|
||||
return div;
|
||||
@@ -377,7 +386,7 @@ function renderToolBoxContent(div, name, inputJson, result, isError) {
|
||||
|
||||
const nameSpan = document.createElement('span');
|
||||
nameSpan.className = 'tool-name';
|
||||
nameSpan.textContent = name;
|
||||
nameSpan.textContent = TOOL_DISPLAY_NAMES[name] || name;
|
||||
header.appendChild(nameSpan);
|
||||
|
||||
if (isError) {
|
||||
|
||||
Reference in new issue
Block a user