Bisher teilte sich eine Budgetablehnung den Ausgang NichtGelaufen mit dem
Herunterfahren. Einmalige Aufgaben wurden den Rest des Tages alle 30 Minuten
erneut abgelehnt (jedes Mal ein Beleg) und liefen nach Mitternacht still zu
Lasten des neuen Tages. Wiederkehrende verfielen still.
- TaskLauf.KeinBudget als eigener Ausgang; der Dispatcher bildet
BudgetExceeded darauf ab.
- Vier Felder an der Aufgabe: BudgetMissCount, LastBudgetMissAt,
DeferredUntil, CatchUpPending (Spalten werden fuer bestehende Datenbanken
nachgeruestet).
- Einmalige Aufgaben werden mitgenommen: Der Termin bleibt erhalten, faellig
ist die Aufgabe wieder ab der naechsten lokalen Mitternacht, nicht vorher.
- Wiederkehrende Aufgaben folgen der Regel des Agenten
(budget.whenExhausted): expire vermerkt den Ausfall und laesst den Termin
verfallen; catchUpOnce fasst alle verpassten Termine zu einem Nachholauf am
naechsten Tag zusammen. Ein regulaer faelliger Termin deckt das Nachholen
mit ab, es bleibt bei einem Lauf.
- Der neue Tag hat Vorfahrt: Mitgenommenes und Nachholaeufe kommen nach allem
regulaer Faelligen, unabhaengig von der Prioritaet.
- Beim ersten Takt eines neuen Tages eine Zusammenfassung je Agent im Log.
- Sichtbar: Die Aufgabenkarte der WebUI zeigt Ausfaelle, Mitnahme und
Nachholen; die Regel ist im Desktop je Agent einstellbar. Nebenbei sind
"Next:"/"Last:" auf der Karte ins Sprachpaket gewandert.
Stufen 2 bis 4 (Reservierung, Spielraum statt pauschalem Anteil, Vorbeugen)
folgen.
Tests: BudgetMissTests (9 neu). 1.238 gruen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
#643: Entscheidungen wecken den Agenten nur noch bei Ablehnung oder gescheiterter
Ausfuehrung, gesammelt in einer Aufgabe je Agent (5 min Ruhefenster), frisch per
@new:agent statt im fortgefuehrten Chatverlauf. Eine einmalige Aufgabe, deren Lauf
wegen Budget oder Herunterfahren gar nicht stattfand, bleibt faellig (Wiedervorlage
nach 30 min) statt mit gesetztem Marker liegenzubleiben.
#641: Rechte stehen in der Werkzeugkonfiguration des Agenten (erlaubt/verboten).
Erlaubtes laeuft, Nicht-Erlaubtes wird einzeln vorgelegt statt verweigert, Verbotenes
gar nicht erst. "Gleichartiges kuenftig erlauben" erteilt eine widerrufbare
Dauerfreigabe je Agent/Werkzeug/Operation; nach drei gleichartigen Freigaben schlaegt
die Oberflaeche sie vor. Aenderungen an Agenten bleiben ausnahmslos freigabepflichtig.
Database: Operation ist das SQL-Schluesselwort; die eigene Zugriffspruefung greift nur
noch ohne Freigabestelle (AgentToolContext.FreigabeGeprueft). WebUI: Rechte-Tabelle je
Werkzeug, Dauerfreigaben mit Widerruf.
Version 0.1.11.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- #578: Abgebrochene Laeufe (Schrittgrenze, Zeitueberschreitung, Abbruch,
Ausnahme) tragen ihre bezahlten Token - vorher 0 in RunUsage, fuer das
Budget unsichtbar.
- #580: WebFetch prueft die aufgeloeste Zieladresse beim Verbinden; ein
erlaubter Name, der auf 127.0.0.1 aufloest, wird gesperrt.
- #575: Dateien entstehen unter Unix mit 0600 (AtomicFile, Protokolle,
FileRW-Anhaengen, state.db), Protokollverzeichnisse mit 0700.
- #576: SIGTERM/SIGINT beenden auch mit Fenster geordnet.
- #593: OpenRouter-Statusdienst wird gestartet.
- #589: Auftragsnachricht nennt aktuelle Zeit, Zeitzone und Termin.
- #581: Unvollstaendiges Argument-JSON erreicht das Werkzeug nicht mehr;
das Modell bekommt eine verstaendliche Rueckmeldung statt Parsertext.
- #591: Weboberflaeche liest die Felder, die API und Ereignisstrom liefern
(Freigaben, Protokoll, Taskboard mit Termin, Werkzeug-Einstellungen,
Tokennutzung); Ereignisstrom in camelCase.
- #592: Chat zeigt Nachrichten nicht mehr doppelt.
- #536 (teilweise): A2A-Antworten tragen Absender und Empfaenger, Parser
wirft nicht mehr; Datums- und Volltextfilter in Agenten-Chats.
- deploy/publish.py: Packager-Pfad net10.0, Schalter --agent-file.
- Version 0.1.4.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
#553 FileRW schreibt atomar. Die Vorkehrung lag seit #241 im selben
Repository und wurde ueberall benutzt - Einstellungen, Sicherungen,
Chat-Zustand, Identity.md - nur der Weg, ueber den Agenten ihre
Arbeitsergebnisse ablegen, ging daran vorbei. Damit stand das Verhaeltnis
auf dem Kopf: geschuetzt war das Eigene, ungeschuetzt das Ergebnis.
append bleibt bewusst nicht atomar; das ginge nur, indem die ganze Datei
neu geschrieben wird, und bei einer grossen Protokolldatei waere das der
falsche Handel.
#554 Wiederaufnahme. Neuer Eintrag AuditStatus.Started, geschrieben VOR
der Wirkung und als einziger nicht "best effort" - auf ihn stuetzt sich
alles Weitere, also laeuft der Aufruf gar nicht erst, wenn er nicht
durchkommt. Neue Kennzeichnung IsRepeatable, getrennt von IsParallelSafe:
Das eine heisst "stoert keinen gleichzeitigen Aufruf", das andere
"richtet zweimal keinen Schaden an". CrashRecovery sichtet beim Start,
was offen blieb, und stuft ein - fuehrt aber nichts aus. Es sichtet und
berichtet; entscheiden soll der Aufrufer.
Dabei kippte eine alte Regel: Bisher wurde ein Abbruch bewusst NICHT
protokolliert. Das war richtig, solange es keinen Eintrag vor dem Aufruf
gab. Jetzt saehe sonst jeder Benutzerabbruch beim naechsten Start aus wie
ein Absturz - bis niemand mehr hinsieht. Deshalb AuditStatus.Cancelled.
#555 Optionale Zustandspruefung IToolStateProbe, umgesetzt in FileRW.
Unknown ist eine vollwertige Antwort, kein Fehlschlag: Ob ein SMTP-Server
angenommen hat, laesst sich nicht feststellen, und ein Werkzeug, das hier
raet, waere schlimmer als eines, das schweigt. Partial gilt ausdruecklich
nicht als geklaert - einen halb angehaengten Text sollte niemand
automatisch geraderuecken.
#556 Auswertung. ListForAgentAsync und SummarizeToolUsageAsync. Die Dauer
wird nur ueber abgeschlossene Aufrufe gemittelt; zaehlten die
Started-Eintraege mit ihrer Dauer 0 mit, saehe jedes Werkzeug doppelt so
schnell aus, wie es ist.
Nebenbei: SqliteStorage kann jetzt Spalten nachruesten. CREATE TABLE IF
NOT EXISTS allein genuegte nicht - bei einer bestehenden Datenbank tut die
Anweisung nichts, und erst das naechste INSERT waere gescheitert, im
Betrieb beim Anwender.
Vier Audit-Tests angepasst: Ein ausgefuehrter Aufruf erzeugt jetzt zwei
Eintraege statt einem. Ein Aufruf, der gar nicht erst laeuft - verweigert,
unbekannt, vorgelegt - hat weiterhin genau einen; der Beginn wird erst
nach Rechtepruefung und Staging geschrieben.
23 neue Tests, 912 gesamt, keine Regression. Build ohne Warnungen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Es gab keine Obergrenze. Ein Agent in einer Schleife — etwa durch gegenseitige
send_message-Aufrufe — konnte unbeaufsichtigt Guthaben verbrennen; die
Credits-Anzeige war rein informativ.
Verbrauchsdaten in der Datenbank
Voraussetzung dafuer ist eine belastbare Erfassung. Bisher lag der Verbrauch in
TokenUsage.json: Bei JEDEM Agenten-Lauf wurde die gesamte Datei geladen, ergaenzt
und neu geschrieben, unter einem globalen Lock. Das waechst quadratisch und ist
der eigentliche Engpass bei vielen Agenten — unabhaengig davon, welche Datenbank
darunter liegt.
RunUsage liegt jetzt in einer eigenen Tabelle mit Ortsdatum, damit ein Tagesbudget
der Wahrnehmung des Benutzers folgt und die Abfrage ohne Zeitzonenrechnerei
auskommt. Betraege werden als Text abgelegt und als decimal gelesen: Ueber REAL zu
gehen wuerde bei Cent-Betraegen Rundungsfehler einsammeln, die sich ueber tausende
Laeufe summieren. Ein Test weist das mit 1000 Buchungen zu je 0,0001 USD nach.
BudgetGuard
Zwei Arten von Grenzen, weil sich Kosten nicht immer beziffern lassen: Liefert der
Anbieter fuer ein Modell keine Preise, greift die Kostengrenze nicht — die
Token-Grenze dagegen immer. Wer sich absichern will, setzt beide. Ist die Summe
wegen fehlender Preise unvollstaendig, steht das in der Begruendung; sonst wirkte
ein niedriger Verbrauch wie ein noch offener Spielraum.
Grenzen gibt es je Agent und je Instanz. Geprueft wird vor der ersten Anfrage,
damit ein erschoepftes Budget gar nichts mehr kostet. Neuer Endzustand
BudgetExceeded.
Nebenbei: Der Namespace Usage kollidierte mit der gleichnamigen Modellklasse fuer
Token-Angaben und heisst jetzt Accounting.
357 Tests gruen (209 Core, 148 Tools).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Geplante Agenten begannen bei jedem Cron-Lauf bei null. Ein Agent, der alle 30
Minuten lief, wusste nichts von seinem letzten Durchgang — er rief dieselben
Quellen ab, zog dieselben Schluesse und konnte keine Entwicklung ueber Zeit
verfolgen. Das war zugleich die groesste Faehigkeitsluecke und eine dauerhafte
Token-Verschwendung.
Speicher-Fundament
SqliteStorage buendelt den Zugang zur Instanz-Datenbank und aktiviert WAL,
busy_timeout und Connection-Pooling. Vorher oeffnete jeder Aufruf eine Verbindung
ohne diese Einstellungen; bei mehreren gleichzeitig schreibenden Agenten gab das
"database is locked". Das sah nach einer Grenze von SQLite aus, war aber nur
fehlende Konfiguration. Zwei Tests decken das gezielt ab.
Gedaechtnis
Typisierte Tabelle statt JSON in einer Wert-Spalte — nur so laesst sich filtern,
sortieren und spaeter auswerten. Das Schema ist schlicht gehalten, damit eine
MySQL-Variante spaeter dieselbe Struktur mit wenigen Dialektunterschieden
bekommen kann.
Der wichtigste Teil ist der optionale Schluessel: Erneutes Merken darunter
aktualisiert den Eintrag, statt einen zweiten anzulegen. Ohne das wuechse das
Gedaechtnis eines halbstuendlich laufenden Agenten um 48 Eintraege pro Tag zur
selben Sache. Beobachtungen ohne Schluessel sammeln sich weiterhin an, wenn ein
Verlauf entstehen soll.
Der Abruf sortiert nach Wichtigkeit, dann Aktualitaet — wesentlich, weil das
Ergebnis begrenzt wird und bei einer Kappung das Wichtigste ueberleben muss.
Zusaetzlich greift eine Zeichenobergrenze, damit ein Abruf den Kontext nicht
sprengt.
Die Trennung privat/geteilt ist absichtlich dieselbe wie beim FileRW-Tool, damit
das Konzept fuer Agenten wiedererkennbar bleibt.
Beim Testen fiel auf, dass das Maskieren der LIKE-Platzhalter falsch war: Die
Zeichen wurden entfernt statt maskiert, wodurch eine Suche nach einem
Prozentzeichen zu einem leeren Muster und damit zu einem Treffer auf alles wurde.
Jetzt mit ESCAPE-Klausel.
338 Tests gruen (190 Core, 148 Tools).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>