Bug: Bei 2+ aufeinanderfolgenden ask_user_choice-Runden wurden ältere
Choice-Chains nur als Text geladen. Claude sah die früheren tool_use/
tool_result-Paare nicht → kein Kontext über bereits beantwortete Fragen
→ Agent stellte dieselben Fragen erneut (Dauerschleife).
Fix: fullChainStartIndex-Logik traversiert jetzt rückwärts durch alle
zusammenhängenden Choice-Chains (erkannt an tool_result mit Iteration 999).
Alle werden vollständig geladen, damit die gesamte Frage-Antwort-Historie
für Claude sichtbar bleibt.
Backend: sb.AppendLine() durch sb.Append()+\n ersetzt für
konsistente Zeilenenden auf allen Plattformen.
Frontend: \r defensiv entfernen vor Regex-Matching, da
JS-Regex (.+)$ kein \r matcht und nur letzte Zeile geparsed wurde.
- HttpResponseMessage mit using disposen (3 Stellen in AnthropicService)
verhindert Socket-Exhaustion unter Windows (2 Connections/Host Limit)
- SSE DisableBuffering() in ChatEndpoint für sofortigen Flush unter Windows
- Execute: stdout/stderr vor WaitForExitAsync lesen statt danach
verhindert Pipe-Deadlock bei vollem Buffer (Windows: 4KB)
- Plan-Modus: Frontend sendet planMode bei Choice-Response mit
Backend-Fallback auf vorherigen Chain entfernt - User-Entscheidung gilt
Plattformspezifische bin/obj/publish-Ordner unter Build/Linux/
und Build/Windows/ statt bin-linux/, obj-linux/, publish/ etc.
- Directory.Build.props: OS-Erkennung setzt BaseOutputPath,
BaseIntermediateOutputPath und MSBuildProjectExtensionsPath
auf Build/{Linux|Windows|macOS}/
- gott.csproj: Vereinfacht auf ein einziges Build/** Exclude
- deploy.sh: publish-Output nach Build/Linux/publish
- OpenClawEndpoint.cs: DB-Pfad relativ zu AppContext.BaseDirectory
- Doku (README, ARCHITECTURE, ARCHITECTURE_QUICK) aktualisiert
_mergeConsecutiveAssistantTexts aktualisierte beim Zusammenführen
aufeinanderfolgender Assistant-Text-Messages die id und createdAt,
aber nicht den sortKey. Dadurch blieb lastKnownMessageId auf dem
niedrigeren sortKey der ersten Message stehen.
Folge: Beim nächsten Poll wurden bereits geladene Messages erneut
geliefert (afterSortKey zu niedrig) → Duplikate im Chat.
lastKnownMessageId wurde pro Poll nur um 1 erhöht statt auf den
tatsächlich höchsten Wert.
- server_tool_use-Blöcke werden jetzt in DB persistiert und in
History-Rekonstruktion als Raw-JSON eingefügt
- Generische *_tool_result-Behandlung (bash_code_execution_tool_result,
code_execution_tool_result etc.) in allen drei Chat-Pfaden:
StreamChat, ChatNonStreaming, RunAgentChat
- ProcessStream: serverToolResultBlocks analog zu webSearchResultBlocks
- BuildHistoryFromDb: server_tool_use + server_tool_result werden
korrekt in Assistant-Content-Array rekonstruiert
- Behebt API 400: tool_use without corresponding tool_result
- Neuer Abschnitt 'Was NICHT ins Memory gehört' im System-Prompt
- Klarstellung: Memory ist agent-übergreifend (über alle Sessions geteilt)
- Keine Session-Kontexte/System-Prompt-Inhalte ins Memory kopieren
- Nur langfristig relevante Infos speichern (Präferenzen, Konventionen)
- tool_end SSE-Event: 500-Zeichen-Limit entfernt (2 Stellen), damit
todo_write und andere Tools beim Streaming vollständig angezeigt werden
- BuildHistoryFromDb: TruncateToolResult (20k) auf tool_result-Messages
angewendet, um Token-Overflow bei History-Rebuild zu verhindern
(609k Tokens > 200k Limit nach awaiting_user_choice)
- TruncateToolResult/MaxToolResultChars auf internal geändert
- TODO.md: todo_write-Bug als erledigt markiert
- MaxHistory (Default: 120): Max History-Messages pro API-Request
- ReminderInterval (Default: 30): System-Prompt Reminder alle N Messages (0 = deaktiviert)
- Beide Werte über Server-Settings-UI konfigurierbar
- Hardcoded Werte in ChatService durch konfigurierbare Felder ersetzt
- Telegram-Bot-Page: Webhook-Secret und Webhook-Section immer sichtbar (hidden-Logik entfernt)
- Agent-Page: Public-Checkbox in scrollbaren Bereich verschoben, Sichtbarkeit-Label hinzugefügt
- Konsistente Bezeichnung: Public → Öffentlich mit Hint-Text
- Session-Page: Redundantes Telegram-Label entfernt
- Telegram-Bots-Überschrift: Icon entfernt (konsistent mit anderen Sektionen)
Problem: systemd setzt WorkingDirectory=/app/gott (= ContentRoot),
aber AppContext.BaseDirectory zeigt auf /app/gott/publish/.
Dadurch existierten zwei appsettings.Production.json – .NET las die
eine, die Server-Settings-UI schrieb die andere. Config-Änderungen
wie PayloadLogging hatten daher keinen Effekt.
Fix: ProductionConfigPath und FallbackConfigPath werden jetzt von
app.Environment.ContentRootPath abgeleitet statt AppContext.BaseDirectory.
- SystemPromptBuilder.BuildReminder(): generiert automatisch Reminder-Text
aus den aktiven Prompt-Blöcken (Identity, Workspace, Memory, etc.)
- Alle ~30 Messages wird ein [System Reminder]-Paar in die History injiziert
(nur nach assistant-Messages, um user/assistant-Alternierung zu wahren)
- History auf maximal 120 Messages begrenzt (älteste werden entfernt)
- ChatContext um PromptBlocks-Property erweitert
- Alle Aufrufer (ChatEndpoint, TelegramService, CronjobService) übergeben
promptBlocks an BuildHistoryFromDb
- Remove tool_choice from AgentEndpoint (create, update, list responses)
- ChatService: automatically set tool_choice='any' when workspace, memory
or skills present, null otherwise. Same for preparer/review/finalizer
- SystemPromptBuilder: remove 3 toolAny-conditional prompt blocks
(KRITISCH, Verhalten, ERINNERUNG)
- Frontend: remove checkbox, badge and JS references
- Agent.ToolChoice DB field preserved for backward compat, no longer read
Wenn eine Telegram-Nachricht von einem nicht verknüpften Chat eingeht:
- Sucht nach Sessions mit diesem Bot, die noch keine Chat-ID haben
- Genau 1 unverknüpfte Session → automatisch zuweisen + Bestätigung
- 0 oder mehrere → Chat-ID anzeigen, manuell im Web-UI zuweisen
Neue DB-Methode: FindUnlinkedSessionsForBot(botId)
Der Tag-Filter in BuildHistoryFromDb filterte alle Messages mit Tag
aus, sofern der Tag nicht dem angeforderten includeTag entsprach.
openclaw-import ist jedoch kein Sub-Agent-Tag (wie preparer/review/
finalizer), sondern ein Herkunfts-Tag und muss immer in der History
enthalten sein.
- AgentRecord: neues IsPublic-Feld mit DB-Migration
- GET /api/agents/available: eigene + public Agents (alle Properties + isOwner)
- GET /api/telegram/bots/available: alle Properties außer Token/Secret + sessionCount
- Agent-Page: Public-Checkbox (andere User können Agent in Sessions verwenden)
- Dashboard: agentMap aus availableAgents gebaut (public Agents fremder User auflösbar)
- Session-Page + Cronjob-Page: Agent-Picker nutzt /available statt /agents
- Agent-Cards: Public- und Fremd-Badges
- Fix: Chat-Button bei Sessions mit public Agent eines anderen Users nicht mehr disabled
Backend:
- New OpenClawEndpoint with GET /api/openclaw/sessions and POST /api/openclaw/import
- Lists all OpenClaw sessions with preview messages, model, summary
- Imports user/assistant text messages (skips tool-use/tool-result)
- Cleans user messages (removes webchat prefixes, cron tags, conversation info blocks)
- Re-import support: deletes previous openclaw-import chains before importing
- New DatabaseService methods: CreateChainForImport, CreateMessageForImport, DeleteOpenClawImport
- Added SortKey to MessageRecord (computed: openclaw-import gets id-10B, else id)
History sorting:
- OpenClaw-imported messages always appear before native messages
- Sort by CASE WHEN tag='openclaw-import' THEN id-10000000000 ELSE id END
- Cursor-based paging updated from beforeId/afterId to beforeSortKey/afterSortKey
- All history queries (GetLatestActive, Before, After, CountBefore) updated
Frontend:
- Dashboard: new 'OpenClaw Import' menu item in session card dropdown
- Modal: shows OpenClaw sessions with metadata, summary, preview messages
- Imported messages display blue 'OC' badge in chat
- API functions: apiGetOpenclawSessions, apiImportOpenclawSession
- History paging updated to use sortKey cursors
BuildReviewMessages() komplett umgebaut:
- Tool-Calls und Tool-Results werden nicht mehr übergeben
- Nur noch die reine Text-Konversation (user/assistant) wird extrahiert
- Aufeinanderfolgende Messages gleicher Rolle werden zusammengeführt
- Korrekte user/assistant-Abwechslung sichergestellt
- Fallback wenn nur Tool-Calls ohne Text vorhanden
- Unnötigen Serialisierungs-Roundtrip für Rollen-Prüfung entfernt
Erwartete Token-Ersparnis: 50-100k+ Input-Tokens pro Review-Runde
bei typischen Worker-Sessions mit vielen write_file/edit_file-Calls.
ARCHITECTURE.md:
- Inhaltsverzeichnis-Nummerierung korrigiert (22-28 statt doppelt 20-21)
- ServerSettingsEndpoint.cs in Projektstruktur ergänzt
- Tabellenbeschreibungen vervollständigt (users, agents, sessions, chains,
messages, cronjobs) mit allen fehlenden Feldern
- ChainRecord/MessageRecord/SessionWithStats Felder aktualisiert
- AutoCommit mention-Beschreibung korrigiert
ARCHITECTURE_QUICK.md:
- ToolService 12 → 13 Tools korrigiert
- Tabellenbeschreibungen analog zur Hauptdoku aktualisiert
Nach dem Streaming werden alle .streamed Elemente entfernt und pollHistory()
rendert die Messages neu aus der DB. Bisher wurden Review-Agent-Messages dabei
als einzelne Bubbles dargestellt (jeder Text-Block + jeder Tool-Call separat),
statt als eine zusammenhängende Review-Bubble wie beim Streaming.
Lösung: _renderMessagesIntoFragment() erkennt jetzt Messages mit tag-Feld
(review/preparer/finalizer) und gruppiert aufeinanderfolgende Messages mit
demselben Tag. _renderReviewGroup() erzeugt daraus eine einzige Review-Bubble
mit Header (Icon + Agent-Name), Tool-Use-Indikatoren und zusammengefasstem
Text-Content - identisch zur Streaming-Darstellung.
Fallback für alte Messages ohne tag-Feld bleibt bestehen (_isReviewMessage).
- esc() um "→" Escaping erweitert (Bug: Anführungszeichen in value="..."-Attributen brachen HTML)
- cache_control: ephemeral zu RunAgentChat() hinzugefügt (Preparer/Review/Finalizer hatten kein Prompt Caching)
- cache_control: ephemeral zu ChatNonStreaming() hinzugefügt (Telegram hatte kein Prompt Caching)
- Trailing-Leerzeile in commands-ui.js bereinigt
- ImageService: PNG-Encoder durch WebP-Encoder ersetzt (Quality 80)
- Bilder werden jetzt immer zu WebP konvertiert (auch kleine)
- DB-Migration: Bestehende PNG/JPEG-Avatare und Session-Images
automatisch zu WebP konvertiert beim Start
- Migration ist idempotent (überspringt bereits konvertierte Bilder)
- Kein Frontend-Code betroffen (Data-URLs sind format-agnostisch)
- Archive messages (loadLatestArchive) now render reply, delete, mark
and share buttons, matching the behavior of _renderMessagesIntoFragment
- Add review-bubble and preparer-bubble detection for archive messages
- Add data-role, data-timestamp attributes for proper reply quoting
- Add isMarked/deletedOn CSS class handling for archive messages
- Also add [Preparer:] to isReviewMsg check in _renderMessagesIntoFragment
for consistency
Kernproblem: Claude vergisst [FORWARD]-Tag → Preparer leitet nie weiter.
Lösung - Logik umgedreht:
- Jede Antwort wird automatisch an Session-Agent weitergeleitet (Default)
- Nur bei explizitem [QUESTION]-Tag wird gestoppt (Rückfrage an User)
- [FORWARD] wird weiterhin erkannt und entfernt, ist aber optional
Weitere Fixes:
- Preparer bekommt eigene History mit includeTag='preparer',
damit er den Kontext seiner vorherigen Rückfragen sieht
- Session-Agent bekommt saubere History ohne Sub-Agent-Messages
(nach Preparer-Phase frisch aus DB geladen)
- [QUESTION] wird im Frontend-Markdown ausgeblendet
- MessageRecord: neues Tag-Feld (null=normal, preparer/review/finalizer=Sub-Agent)
- DatabaseService: Migration tag-Spalte, INSERT-Statements erweitert
- AnthropicService: RunAgentChat setzt Tag=agentType bei allen 4 SaveMessage-Aufrufen
- ChatService: BuildHistoryFromDb filtert getaggte Messages aus API-History
Sub-Agent-Messages bleiben in der DB (Frontend-Anzeige), werden aber
nie an die Claude API geschickt – löst das Problem für Preparer,
Review und Finalizer gleichermaßen.
- Neues optionales Session-Feld 'preparerAgentId' (DB + Model + API)
- PreparerContext im ChatContext für Agent-Konfiguration
- RunPreparer() in AnthropicService: führt Preparer vor dem Worker aus
- [FORWARD] → aufbereiteter Prompt wird an Session-Agent weitergegeben
- Ohne [FORWARD] → Rückfrage an User, Flow stoppt (preparer_query)
- Preparer-System-Prompt: erklärt Rolle, [FORWARD]-Mechanismus, Vorarbeit
- Preparer kann eigene Tools + Fähigkeiten aktiv nutzen
- ChatEndpoint: Preparer-Phase vor StreamChat integriert
- Frontend: SSE-Events (preparer_start/text/tool_use/done)
- Preparer-Bubble (Info-Farbe) mit Status Weitergeleitet/Rückfrage
- [Preparer: Name] → hübscher Header, [FORWARD] ausgeblendet
- [Vorbereitet von Name] → dezenter Header in User-Bubble
- Agent-Picker im Session-Form (vor Review-Agent)