Prompt History und Verbrauchsauswertung (#660), englische Hauptsprache (#661)

Prompt history: every run records its transcript (task, each model step with
tokens and cost, tool calls and results, engine follow-ups) - bounded in size,
scrubbed of recognisable secrets, system prompts stored once per text.
Retention in days per instance (default 14) and per agent (0 = never, -1 =
forever); an hourly janitor deletes what is past it, "never" also purges.

Usage analysis over run receipts: filter by period, agent, model, event, status,
cost and free text; sort by every column; totals over the whole filter; hourly
or daily series grouped by agent, model or event; markers for budget denials and
model changes; run detail with receipt, transcript, tool calls and approvals.

WebUI: Analysis > Token usage > Runs / Timeline, run detail, Prompt History with
retention settings. New code, comments and texts in English; texts come from
language packs (i18n/en.json, de.json) via modules/i18n.js. CLAUDE.md records
English as the main language.

Version 0.1.12.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-19 15:33:09 +02:00
co-authored by Claude Opus 5
parent 2f0361278b
commit 5adf4c1ca6
40 changed files with 3521 additions and 10 deletions
+306
View File
@@ -1415,3 +1415,309 @@ button.klein {
margin-top: 10px;
font-size: 14px;
}
/* ─── Token usage analysis and prompt history (#660) ─── */
.nav-unterlink {
padding-left: 42px;
font-size: 13px;
}
.seitenleiste.kollabiert .nav-unterlink {
display: none;
}
.filter-leiste {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: 10px 14px;
margin: 12px 0 16px;
}
.filter-feld {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 12px;
color: var(--gedaempft);
}
.filter-feld select,
.filter-feld input {
min-width: 140px;
}
.filter-suche input {
min-width: 220px;
}
.filter-eigen {
display: flex;
align-items: center;
gap: 6px;
}
.filter-aktionen {
display: flex;
gap: 6px;
}
.kennzahlen-raster {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px;
}
.kennzahl {
border: 1px solid var(--divider);
padding: 10px 12px;
}
.kennzahl-wert {
font-size: 20px;
font-weight: 600;
}
.kennzahl-titel {
font-size: 12px;
color: var(--gedaempft);
}
.tabelle-scroll,
.diagramm-scroll {
overflow-x: auto;
}
.daten-tabelle td.zahl,
.daten-tabelle th.zahl {
text-align: right;
font-variant-numeric: tabular-nums;
}
.sortier-knopf {
background: none;
border: 0;
padding: 0;
font: inherit;
color: inherit;
text-transform: inherit;
letter-spacing: inherit;
cursor: pointer;
}
.klickbar {
cursor: pointer;
}
.klickbar:focus-visible {
outline: 2px solid var(--accent);
}
.blaettern {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-top: 12px;
}
.zurueck-link {
display: inline-block;
margin-bottom: 8px;
}
.diagramm-steuerung {
display: flex;
flex-wrap: wrap;
gap: 8px 24px;
margin-bottom: 12px;
}
.zeitverlauf .raster {
stroke: var(--divider);
stroke-width: 1;
}
.zeitverlauf .achse {
fill: var(--gedaempft);
font-size: 11px;
}
.zeitverlauf .balken {
cursor: pointer;
}
.zeitverlauf .balken:hover,
.zeitverlauf .balken:focus {
opacity: 0.8;
outline: none;
}
.zeitverlauf .ereignis line {
stroke-width: 1.5;
stroke-dasharray: 4 3;
}
.zeitverlauf .ereignis-budget line,
.zeitverlauf .ereignis-budget path {
stroke: var(--gefahr);
fill: var(--gefahr);
}
.zeitverlauf .ereignis-modell line,
.zeitverlauf .ereignis-modell path {
stroke: var(--accent);
fill: var(--accent);
}
.legende {
display: flex;
flex-wrap: wrap;
gap: 8px 16px;
margin-top: 10px;
font-size: 13px;
}
.legende-eintrag {
display: inline-flex;
align-items: center;
gap: 6px;
}
.legende-farbe {
width: 12px;
height: 12px;
display: inline-block;
}
.legende-marke {
width: 0;
height: 12px;
display: inline-block;
border-left: 2px dashed;
}
.legende-marke.ereignis-budget {
border-color: var(--gefahr);
}
.legende-marke.ereignis-modell {
border-color: var(--accent);
}
.transkript-system {
margin-bottom: 12px;
}
.transkript-eintrag {
border-left: 3px solid var(--divider);
padding: 6px 0 6px 12px;
margin: 10px 0;
}
.transkript-eintrag.art-user { border-left-color: var(--accent); }
.transkript-eintrag.art-assistant { border-left-color: var(--erfolg); }
.transkript-eintrag.art-tool_result { border-left-color: var(--warnung); }
.transkript-eintrag.art-engine,
.transkript-eintrag.art-event { border-left-color: var(--gedaempft); }
.transkript-kopf {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-bottom: 4px;
}
.transkript-text {
white-space: pre-wrap;
word-break: break-word;
max-height: 420px;
overflow-y: auto;
margin: 4px 0;
}
.transkript-aufruf {
margin-top: 6px;
}
.schlichte-liste {
list-style: none;
padding: 0;
margin: 0;
}
.schlichte-liste li {
padding: 4px 0;
}
.verlauf-eintrag {
border: 1px solid var(--divider);
padding: 10px 12px;
margin-bottom: 10px;
}
.verlauf-eintrag:hover {
background: var(--surface-hover);
}
.verlauf-kopf {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
margin-bottom: 6px;
}
.verlauf-zeile {
display: flex;
gap: 10px;
font-size: 14px;
margin: 2px 0;
}
.verlauf-marke {
flex: 0 0 80px;
color: var(--gedaempft);
font-size: 12px;
text-transform: uppercase;
}
.verlauf-text {
flex: 1;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
white-space: pre-wrap;
word-break: break-word;
}
.aufbewahrung input[type="number"] {
width: 80px;
}
@media (max-width: 768px) {
.filter-feld select,
.filter-feld input,
.filter-suche input {
min-width: 0;
width: 100%;
}
.filter-feld {
flex: 1 1 140px;
}
.verlauf-zeile {
flex-direction: column;
gap: 2px;
}
}
span.klein,
div.klein,
td.klein {
font-size: 12px;
}