8ab9d99abe87cd1fb60acf21308fa496825d7a12
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b568a45de3 |
Wiederaufnahme nach Absturz, Nachschau und Auswertung (#553-#556)
#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> |
||
|
|
ea3844006f |
Harness gegen stillen Verlust gehaertet (#547-#551)
Fuenf Befunde mit einem gemeinsamen Fehlermodus: Keiner erzeugt eine Fehlermeldung. Der Lauf wird fertig, das Ergebnis sieht plausibel aus, und nur die Qualitaet ist schlechter. #547 Der Begleittext zum Werkzeugaufruf ging verloren. AssistantWithToolCalls baute eine neue Nachricht aus nur den Aufrufen; der Text, den das Modell daneben geschrieben hatte, fiel weg. Damit verlor das Modell zwischen zwei Schritten seinen eigenen Plan, und im Audit stand, dass ein Werkzeug lief, nicht warum. #548 finish_reason wurde nirgends gelesen. Eine an der Ausgabegrenze abgeschnittene Antwort galt als fertiges Ergebnis. Das trifft besonders Laeufe im Hintergrund, wo niemand zusieht. Neuer Status Truncated: Das Teilergebnis geht weiter, aber gekennzeichnet. #549 reasoning_details wurde verworfen. Bei Werkzeugnutzung muss der Denkverlauf unveraendert zurueck, sonst beginnt ein Thinking-Modell jedes Mal von vorn. Wird jetzt als rohes JSON durchgereicht - ohne Auslegung, weil Reihenfolge und Signatur daran haengen. #550 Die Anfrage verlangt jetzt einen Anbieter, der alle mitgeschickten Parameter beherrscht. Ohne das durfte ein Anbieter cache_control, reasoning oder sogar tools stillschweigend uebergehen - der Lauf lieferte dann eine gewoehnliche Textantwort, wo ein Werkzeugaufruf hingehoert haette. Dazu usage.include: der abgerechnete Betrag schlaegt die Eigenrechnung, die als Rueckfallebene bleibt. Denktiefe je Agent einstellbar, Vorgabe off. #551 Werkzeuge eines Zuges laufen gleichzeitig, sofern sie sich dafuer freigeben. Die Vorgabe von IsParallelSafe ist false, weil die falsche Antwort hier nicht auffaellt: Zwei schreibende Aufrufe auf derselben Datei scheitern nicht zuverlaessig, sondern gelegentlich. Freigegeben ist bisher nur WebFetch - es liest ausschliesslich. Die Reihenfolge der Ergebnisse folgt den Aufrufen, nicht der Fertigstellung; daran haengen die tool_call_id-Zuordnung und der Cache-Praefix. 27 neue Tests, 887 gesamt, keine Regression. Build ohne Warnungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
cffd6f4b77 |
Bugtracker-Durchgang: 13 Bugs behoben, Build ohne Warnungen
Alle Behebungen auf der Linux-Test-VM gegengeprueft (Ubuntu, .NET 10.0.111): Build 0 Warnungen / 0 Fehler, 637 Tests gruen, 1 uebersprungen (WindowsFact). Sicherheit und Zielplattform #373 PathBoundary.Canonicalize fiel offen aus. File.ResolveLinkTarget wirft fuer einen fehlenden Abschnitt FileNotFoundException; der catch(IOException) verliess daraufhin die GANZE Aufloesung mit dem unaufgeloesten Pfad - und der besteht jede Praefixpruefung. Der Symlink-Schutz war damit bei jedem Schreibvorgang wirkungslos. Jetzt ueber FileSystemInfo.LinkTarget, und TryCanonicalize meldet "nicht bestimmbar", statt fail-open durchzureichen. #374 WorkspacePath weist den Backslash rundheraus ab, wie den Doppelpunkt. Eine Schreibweise statt einer Sonderregel je Windows-Form. #375 Log-Verzeichnis: leer heisst "Anwendungseinstellung"; ein relativer Wert zaehlt gegen das Instanzverzeichnis, nicht gegen das Arbeitsverzeichnis des Prozesses. Ein systemd-Dienst landet nicht mehr auf /Logs. Agentenkommunikation #206 Delegationskette gegen A->B->A (Test A13). Zyklusfrei per Bauart, dazu MaxDelegationDepth gegen die Staffel, die niemand beauftragt hat. #461 Zwei unabhaengige Ketten ueber Kreuz - beim Beheben von #206 gefunden und reproduziert. Ein delegierter Lauf wartet nur noch begrenzt auf ein fremdes Gate; ein Chat vom Menschen reiht sich weiter unbegrenzt ein. #234 Instanz-Id wird durchgereicht statt aus einem nur beilaeufig gesetzten Feld gelesen. Betrieb und Oberflaeche #376 Log-Ansicht chronologisch statt gruppiert je Moduldatei, mit Stacktraces an ihrer Meldung - auch ueber Taktgrenzen hinweg. #377 Info-Tabelle: feste Spaltenbreiten, damit ein langer Aenderungstext den anderen Spalten nicht den Platz nimmt. #378 Sicherung: Mindestabstand zwischen Ueberschrift und Schaltflaechenleiste. #379 Hellmodus: drei von vier gedaempften Textpinseln lagen unter 4,5:1. Die helle Palette ist als Ganzes verschoben, damit die Staffelung sichtbar bleibt statt auf einen Wert zusammenzufallen. Hygiene #233 stock_add: der Indexstand wird innerhalb der Sperre festgehalten. #235 Zeitumstellung: eine nicht existierende Ortszeit wird auf den ersten Zeitpunkt nach der Luecke verschoben statt uebersprungen (R4, R5). #236 45 Nullable-Warnungen und eine CA1416 - nicht unterdrueckt, sondern die Stellen so umgebaut, dass die Zusage nachvollziehbar wird. Mail meldet jetzt, WELCHER Zugangsschluessel fehlt, statt an einer KeyNotFoundException zu scheitern. #203 Kompaktiert wird vor dem API-Aufruf statt danach; die gemessenen Prompt-Groessen kalibrieren die Schaetzung je Modell. Neu: tests/ClawdDotNet.App.Tests - fuer #375 und #376 gab es keinen Ort fuer Tests. Dazu Regressionstests fuer jede Behebung; jeder wurde gegen den alten Stand geprueft, damit belegt ist, dass er den Fehler faengt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
b5bf97ae74 | feat(ui): complete Avalonia UI port with 7 main pages, tool settings & top MenuBar | ||
|
|
cbb8ac22bc |
SSRF-Schutz, Pfadpruefung und Retry-Logik
S5 — Die Domain-Whitelist wurde nur auf die Ausgangs-URL angewendet, HttpClient folgte Weiterleitungen aber selbst. Eine erlaubte Domain konnte damit auf beliebige interne Adressen weiterleiten: Router, NAS, der Git-Server im LAN, Cloud-Metadatendienste. Der Agent haette deren Inhalt zurueckgeliefert. UrlGuard prueft Schema, private und lokale Netzbereiche sowie die Whitelist. AllowAutoRedirect ist abgeschaltet; Weiterleitungen werden einzeln aufgeloest und JEDER Zwischenschritt erneut geprueft, begrenzt auf fuenf Spruenge. Nebenbei behoben: Die alte www-Behandlung ersetzte die Zeichenfolge ueber den ganzen Hostnamen, aus mywww.example.com wurde myexample.com. Und die Subdomain-Pruefung achtet jetzt auf den Punkt, sodass example.com.attacker.net nicht mehr als Treffer fuer example.com durchgeht. S6 — Die Pfadpruefung in FileRW verglich nur Zeichenketten-Praefixe. Ohne abschliessenden Verzeichnistrenner erlaubte ein Root wie Agent-X\Workspace damit auch Zugriffe auf Agent-X\Workspace-Backup. WorkspacePath vergleicht jetzt auf Verzeichnisgrenzen und lehnt zusaetzlich absolute Pfade, UNC-Freigaben und Alternate Data Streams ab. Das Dateisystem wird in den Tests bewusst nicht abstrahiert — sie sollen die echte Windows-Pfadsemantik pruefen. Eine Abstraktion wuerde genau die Fehlerklasse verstecken, um die es geht. B12 — Der Client warf bei jedem Nicht-2xx sofort; ein einzelnes HTTP 429 beendete damit einen kompletten geplanten Lauf, obwohl Rate-Limits und kurze 5xx bei OpenRouter Normalbetrieb sind. RetryPolicy wiederholt 408/425/429/5xx mit exponentiellem Backoff und Streuung, respektiert ein Retry-After des Servers und deckelt die Wartezeit. Dauerhafte Fehler wie 401 werden nicht wiederholt. Die Wartefunktion ist injizierbar, damit die Tests nicht wirklich warten. 264 Tests gruen (116 Core, 148 Tools). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
69b5704add |
Prompt-Caching, Tool-Ergebnis-Kappung und Kostenerfassung
T1 — Prompt-Caching. Bisher wurde bei jedem Schritt eines Runs der komplette Prompt neu berechnet, inklusive Tool-Definitionen und System-Prompt, die sich nie aendern. Bei zehn Schritten und einem 15k-Praefix sind das 150.000 statt 15.000 Eingabe-Tokens. ChatMessage bekommt dafuer einen eigenen JsonConverter: Der Inhalt geht weiterhin als String raus, bei gesetztem CacheBreakpoint jedoch als Blockarray mit cache_control. Beim Lesen werden beide Formate akzeptiert, damit bestehende ChatContext.json weiter geladen werden koennen. PromptCache setzt zwei Breakpoints: einen auf den System-Prompt (deckt Tool-Definitionen und System-Prompt ab) und einen rollierenden auf die letzte Nachricht mit Inhalt. Vorherige Markierungen werden vorher entfernt, damit sie sich nicht ansammeln. Aktivierung ueber promptCaching: auto (Default, aktiv fuer Modelle mit Unterstuetzung), on oder off. Der wichtigste Test dazu prueft die Praefix-Stabilitaet: Der System-Prompt muss ueber alle Schritte zeichengleich serialisiert werden. Ein einziger Zeitstempel darin wuerde den Cache still verwerfen — die Kosten blieben unveraendert, ohne dass es irgendwo auffiele. T9 — Usage liest prompt_tokens_details.cached_tokens; die Zahl wird bis in AgentRunResult durchgereicht. Ohne sie liesse sich die Wirkung nicht belegen. T2 — Tool-Ergebnisse werden jetzt zentral in ExecuteToolCallAsync gekappt (maxToolResultChars, Default 16.000). Bisher konnte ein einzelner WebFetch mit dem 512-KB-Standardlimit rund 130.000 Tokens in EINER Antwort erzeugen; die Compaction griff erst danach, bezahlt war der Request laengst. T3 — Die Zusammenfassung beim Kompaktieren laeuft ueber ein konfigurierbares summaryModel (Default gemini-2.5-flash) statt ueber das teure Agentenmodell. B4 — AgentRunResult fuehrt Prompt- und Completion-Tokens getrennt; die Kostenanzeige schaetzte bisher 50/50, real liegt das Verhaeltnis eher bei 95:5. Die veraltete Preistabelle bleibt offen. Neue Einstellungen sind im PropertyGrid sichtbar und werden vom AgentEditor bei neuen Agenten mitgeschrieben. Alle 91 Tests gruen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6bbe9f9a80 |
B2 beheben: Chat-Laeufe pro Agent serialisieren
Der Konversationskontext _chatContexts[agentId] ist eine geteilte List<ChatMessage>. Nur der Lookup lief unter Lock, alle Add-Aufrufe im Schleifenkoerper waren ungeschuetzt. Da WebView, ToolJob-Wakeups und AgentComm denselben Agenten gleichzeitig ansprechen koennen, verschraenkten sich ihre Nachrichten zu einer ungueltigen Tool-Sequenz, die die API mit HTTP 400 ablehnt. ChatAsync laeuft jetzt hinter einem SemaphoreSlim(1,1) pro Agent; verschiedene Agenten bleiben unabhaengig. Die Timeout-Uhr startet erst nach dem Eintritt, damit Wartezeit in der Warteschlange den Lauf nicht aufzehrt. Zwei Folgeprobleme mit demselben Ursprung: - _runningChats hielt nur EINE CancellationTokenSource je Agent; der zweite Lauf ueberschrieb den ersten. AbortChat brach dadurch nur einen ab, der andere lief bis ins Run-Timeout. Jetzt eine Liste, die auch wartende Laeufe erfasst. - ExecuteToolCallAsync fing OperationCanceledException mit ab und gab sie als Tool-Ergebnis zurueck, wodurch der Abbruch erst einen Schritt spaeter griff. Cancellation wird nun durchgereicht. Ausserdem: send_message an den eigenen Agenten wird abgelehnt — es waere mit dem neuen Gate in einen Deadlock gelaufen. Neu: GetChatContext(agentId) als Momentaufnahme des Kontexts, fuer Diagnose und Kontextgroessen-Anzeige. Build-Fix: Das WinForms-Projekt globbt **/*.cs und kompilierte dadurch die Test-Quellen mit. tests\** wird jetzt wie src\** ausgeschlossen. Alle 49 Tests gruen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
667cecce25 |
Testfundament aufbauen und Bestandsaufnahme dokumentieren
IChatCompletionClient aus OpenRouterClient extrahiert, damit AgentEngine und ContextCompactor ohne echte API-Aufrufe testbar sind. Neues Testprojekt tests/ClawdDotNet.Core.Tests (xUnit, Shouldly, NSubstitute, FsCheck) mit: - FakeChatClient (programmierbare Antwortfolgen, Deep-Copy der Requests) - ContextInvariants (prueft die API-Regeln fuer tool_call-Paarung) - Conversation-Builder fuer gueltige Testkonversationen - 26 Tests: Compaction, LoopGuard, 2 Property-Tests 10 Tests sind bewusst rot — sie reproduzieren die Bugs B1, B3 und B14 aus der Bestandsaufnahme und werden mit den Fixes gruen. Ausserdem: fehlende Tool-Projekte in slnx ergaenzt, Test-Pakete im packageSourceMapping der NuGet.Config eingetragen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |