Entscheidungen aus dem Testbetrieb umgesetzt (#572): #577 #579 #581 #589 #193 #205 #594 #595 #597 #598 #599 #588
- Engine: leere Antworten nachfassen, Aufgaben enden mit Ergebniszeile (EmptyResponse/Incomplete), gleiche Fehlschlaege erkennen (RepeatedFailure), Zeitzeile vor Chatnachrichten, Werkzeugergebnisse gerahmt, Vorpruefung vor dem Staging, Belegkosten wie RunUsage - Staging: gescheiterte Freigaben als Failed; AgentEditor-Aenderungen freigabepflichtig, Selbstbearbeitung gesperrt (allowSelfEdit) - Taskboard: Termine beim Anlegen pruefen, naechster/letzter Lauf, pausieren, Sofortlauf, Kostenprognose, Hinweis auf wachsenden Kontext; Jobs-Reiter und /api/jobs entfernt - Release: Instanzmanager samt Weboberflaeche im Paket, setup.json fragt manager.json ab, Token nicht mehr ins systemd-Journal Version 0.1.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,8 +43,9 @@ async function ladeVerbrauch() {
|
||||
);
|
||||
|
||||
try {
|
||||
const laeufe = await api("/usage?limit=100");
|
||||
const [laeufe, prognose] = await Promise.all([api("/usage?limit=100"), erstellePrognoseKarte()]);
|
||||
container.replaceChildren();
|
||||
if (prognose) container.append(prognose);
|
||||
|
||||
if (!laeufe || laeufe.length === 0) {
|
||||
container.append(
|
||||
@@ -162,6 +163,83 @@ async function ladeVerbrauch() {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Kostenprognose (#595) ───
|
||||
|
||||
const GRUNDLAGE_TEXT = {
|
||||
Laeufe: (n) => `Ø letzte ${n} Läufe`,
|
||||
Agent: (n) => `Ø des Agenten (${n} Läufe)`,
|
||||
Schaetzung: () => "Schätzung – noch kein Lauf",
|
||||
Unbekannt: () => "keine Grundlage"
|
||||
};
|
||||
|
||||
async function erstellePrognoseKarte() {
|
||||
let p;
|
||||
try {
|
||||
p = await api("/usage/forecast");
|
||||
} catch {
|
||||
return null; // ohne Taskboard keine Prognose - die Verbrauchsansicht bleibt trotzdem
|
||||
}
|
||||
if (!p) return null;
|
||||
|
||||
const kacheln = erstelleElement("div", { klasse: "kachel-gitter" });
|
||||
kacheln.append(
|
||||
erstelleStatKachel("Prognose je Tag", formatiereKosten(p.totalPerDay)),
|
||||
erstelleStatKachel("Prognose je Monat (30 Tage)", formatiereKosten(p.totalPerMonth)),
|
||||
erstelleStatKachel("davon Aufgaben je Tag", formatiereKosten(p.tasksPerDay)),
|
||||
erstelleStatKachel("sonstige Läufe je Tag (Ø 7 Tage)", formatiereKosten(p.otherPerDay))
|
||||
);
|
||||
|
||||
const hinweise = [];
|
||||
if (p.withoutBasis > 0) {
|
||||
hinweise.push(erstelleElement("p", {
|
||||
klasse: "gedaempft text-klein",
|
||||
text: `${p.withoutBasis} Aufgabe(n) ohne Grundlage (kein Lauf, kein Modellpreis) – nicht in der Summe enthalten.`
|
||||
}));
|
||||
}
|
||||
if (Number(p.oneOffOpen) > 0) {
|
||||
hinweise.push(erstelleElement("p", {
|
||||
klasse: "gedaempft text-klein",
|
||||
text: `Offene einmalige Aufgaben kosten zusätzlich etwa ${formatiereKosten(p.oneOffOpen)}.`
|
||||
}));
|
||||
}
|
||||
hinweise.push(erstelleElement("p", {
|
||||
klasse: "gedaempft text-klein",
|
||||
text: "Grundlage je Aufgabe: Mittelwert ihrer letzten Läufe, sonst der des Agenten, sonst eine Schätzung aus Promptlänge und Listenpreis (eher zu hoch)."
|
||||
}));
|
||||
|
||||
const tabelle = erstelleElement("table", { klasse: "daten-tabelle" });
|
||||
tabelle.append(
|
||||
erstelleElement("thead", {},
|
||||
erstelleElement("tr", {},
|
||||
erstelleElement("th", { text: "Aufgabe" }),
|
||||
erstelleElement("th", { text: "Agent" }),
|
||||
erstelleElement("th", { text: "Läufe/Tag", stil: "text-align: right;" }),
|
||||
erstelleElement("th", { text: "je Lauf", stil: "text-align: right;" }),
|
||||
erstelleElement("th", { text: "Grundlage" }),
|
||||
erstelleElement("th", { text: "je Tag", stil: "text-align: right;" })
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const tbody = erstelleElement("tbody");
|
||||
for (const a of p.tasks || []) {
|
||||
const grundlage = (GRUNDLAGE_TEXT[a.basis] || (() => a.basis))(a.sample);
|
||||
tbody.append(
|
||||
erstelleElement("tr", {},
|
||||
erstelleElement("td", { text: a.oneOffOpen ? `${a.title} (einmalig)` : a.title }),
|
||||
erstelleElement("td", { klasse: "text-klein", text: a.agentId || "—" }),
|
||||
erstelleElement("td", { stil: "text-align: right;", text: String(a.runsPerDay) }),
|
||||
erstelleElement("td", { stil: "text-align: right;", text: a.costPerRun == null ? "—" : formatiereKosten(a.costPerRun) }),
|
||||
erstelleElement("td", { klasse: "gedaempft text-klein", text: grundlage }),
|
||||
erstelleElement("td", { stil: "text-align: right;", text: formatiereKosten(a.costPerDay) })
|
||||
)
|
||||
);
|
||||
}
|
||||
tabelle.append(tbody);
|
||||
|
||||
return erstelleKarte("Kostenprognose", [kacheln, ...hinweise, tabelle]);
|
||||
}
|
||||
|
||||
function erstelleStatKachel(titel, wert) {
|
||||
const kachel = erstelleElement("div", { klasse: "stat-kachel karte" });
|
||||
kachel.append(
|
||||
|
||||
Reference in New Issue
Block a user