diff --git a/wwwroot/index.html b/wwwroot/index.html
index d3e87e1..af60dd3 100644
--- a/wwwroot/index.html
+++ b/wwwroot/index.html
@@ -223,6 +223,19 @@
+
+
+
+ Tokens, Dauer und Iterationen nach jeder Antwort
+
+
+
+
+
Daten
diff --git a/wwwroot/js/chat.js b/wwwroot/js/chat.js
index d3bb3df..7f3df8f 100644
--- a/wwwroot/js/chat.js
+++ b/wwwroot/js/chat.js
@@ -1,13 +1,30 @@
// ── Helpers ──
+function _prettyModelName(model) {
+ if (!model) return '?';
+ // claude-sonnet-4-20250514 → Sonnet 4
+ // claude-opus-4-6 → Opus 4.6
+ // claude-haiku-3-5 → Haiku 3.5
+ const m = model.match(/claude-(\w+)-(\d+)(?:-(\d+))?/);
+ if (m) {
+ const family = m[1].charAt(0).toUpperCase() + m[1].slice(1);
+ const major = m[2];
+ const minor = m[3];
+ // minor > 20000000 ist ein Datums-Suffix, kein Minor-Version
+ if (minor && minor.length <= 2) return family + ' ' + major + '.' + minor;
+ return family + ' ' + major;
+ }
+ return 'Unbekannt';
+}
+
function buildMetaBadges(d) {
const badges = [];
- badges.push(d.model || '?');
- badges.push('In: ' + (d.inputTokens || 0));
- badges.push('Out: ' + (d.outputTokens || 0));
- if (d.cacheCreationTokens > 0) badges.push('Cache-Write: ' + d.cacheCreationTokens);
- if (d.cacheReadTokens > 0) badges.push('Cache-Read: ' + d.cacheReadTokens);
- if ((d.iterations || 0) > 1) badges.push('Iterations: ' + d.iterations);
+ badges.push(_prettyModelName(d.model));
+ badges.push('Tokens: ' + (d.inputTokens || 0) + ' / ' + (d.outputTokens || 0));
+ if (d.cacheCreationTokens > 0 || d.cacheReadTokens > 0) {
+ badges.push('Cache: ' + (d.cacheReadTokens || 0) + ' / ' + (d.cacheCreationTokens || 0));
+ }
+ if ((d.iterations || 0) > 1) badges.push('Iterationen: ' + d.iterations);
if (d.durationMs) badges.push((d.durationMs / 1000).toFixed(1) + 's');
if (d.stopReason && d.stopReason !== 'end_turn' && d.stopReason !== 'tool_use') badges.push('Stop: ' + d.stopReason);
return badges;
@@ -17,6 +34,7 @@ function addChainMetaBubble(d, streamed) {
if (!d || !d.model) return;
// Chain noch nicht finalisiert (läuft noch) → nicht anzeigen
if (!d.inputTokens && !d.outputTokens && !d.durationMs) return;
+ if (!isChainMetaVisible(d)) return;
const badges = buildMetaBadges(d);
const div = document.createElement('div');
div.className = 'chain-meta';
diff --git a/wwwroot/js/history.js b/wwwroot/js/history.js
index 998bc90..82b0528 100644
--- a/wwwroot/js/history.js
+++ b/wwwroot/js/history.js
@@ -170,7 +170,7 @@ async function loadLatestArchive() {
fragment.appendChild(div);
}
// Chain-Meta-Badges nach jeder Chain einfügen
- if (entry.chain) {
+ if (entry.chain && isChainMetaVisible(entry.chain)) {
const badges = buildMetaBadges(entry.chain);
const metaDiv = document.createElement('div');
metaDiv.className = 'chain-meta archived';
diff --git a/wwwroot/js/pages/settings-page.js b/wwwroot/js/pages/settings-page.js
index 3964cad..3e1dc59 100644
--- a/wwwroot/js/pages/settings-page.js
+++ b/wwwroot/js/pages/settings-page.js
@@ -4,7 +4,8 @@ const SETTINGS_KEY = 'settings';
const SETTINGS_DEFAULTS = {
pageWidth: 900,
- toolCallDisplay: 'modifications' // 'all' | 'modifications' | 'hidden'
+ toolCallDisplay: 'modifications', // 'all' | 'modifications' | 'hidden'
+ chainMetaDisplay: 'sometimes' // 'always' | 'sometimes' | 'never'
};
function loadSettings() {
@@ -36,12 +37,14 @@ registerPage('settings', {
const slider = document.getElementById('settingPageWidth');
const display = document.getElementById('settingPageWidthValue');
const toolCallSelect = document.getElementById('settingToolCallDisplay');
+ const chainMetaSelect = document.getElementById('settingChainMetaDisplay');
const resetBtn = document.getElementById('settingsResetBtn');
const s = loadSettings();
slider.value = s.pageWidth;
display.textContent = s.pageWidth + 'px';
toolCallSelect.value = s.toolCallDisplay;
+ chainMetaSelect.value = s.chainMetaDisplay;
slider.addEventListener('input', () => {
display.textContent = slider.value + 'px';
@@ -60,6 +63,12 @@ registerPage('settings', {
saveSettings(s);
});
+ chainMetaSelect.addEventListener('change', () => {
+ const s = loadSettings();
+ s.chainMetaDisplay = chainMetaSelect.value;
+ saveSettings(s);
+ });
+
const backupBtn = document.getElementById('settingsBackupBtn');
if (backupBtn) backupBtn.addEventListener('click', async () => {
backupBtn.disabled = true;
@@ -82,6 +91,7 @@ registerPage('settings', {
slider.value = SETTINGS_DEFAULTS.pageWidth;
display.textContent = SETTINGS_DEFAULTS.pageWidth + 'px';
toolCallSelect.value = SETTINGS_DEFAULTS.toolCallDisplay;
+ chainMetaSelect.value = SETTINGS_DEFAULTS.chainMetaDisplay;
});
},
destroy() {}
diff --git a/wwwroot/js/ui.js b/wwwroot/js/ui.js
index dfd4bef..2070b53 100644
--- a/wwwroot/js/ui.js
+++ b/wwwroot/js/ui.js
@@ -257,6 +257,21 @@ function isToolVisible(toolName) {
return MODIFICATION_TOOLS.includes(toolName);
}
+// ── Chain Meta Visibility ──
+
+function isChainMetaVisible(chainData) {
+ const mode = loadSettings().chainMetaDisplay;
+ if (mode === 'always') return true;
+ if (mode === 'never') return false;
+ // 'sometimes' – nur bei auffälligen Chains anzeigen
+ if (!chainData) return false;
+ const inOut = (chainData.inputTokens || 0) + (chainData.outputTokens || 0);
+ if (inOut >= 10000) return true;
+ if ((chainData.iterations || 0) >= 25) return true;
+ if ((chainData.durationMs || 0) >= 90000) return true;
+ return false;
+}
+
// ── Tool Boxes ──
function addToolBoxLoading(name) {