- Neuer ServerSettingsService: zentrale Settings in SQLite mit In-Memory-Cache
- Auto-Migration: bestehende appsettings.Production.json wird einmalig in DB übernommen
- Alle Services umgestellt: IConfiguration → ServerSettingsService (dynamisch, kein Neustart)
- Port bleibt als einziges Setting in appsettings.Production.json (erfordert Neustart)
- ServerSettingsEndpoint: liest/schreibt DB statt JSON-Datei, Port als Sonder-Setting
- IConfiguration komplett entfernt aus allen Services (ChatService, ToolService, AnthropicService,
OpenAiService, KreaService, TelegramService, KeyScannerService, GitHubEventScannerService)
- AuthMiddleware: KreaApiKey dynamisch aus DB
- appsettings.json bereinigt: nur noch Port und Logging
- Dokumentation aktualisiert (ARCHITECTURE.md, ARCHITECTURE_QUICK.md, README.md)
Backend:
- is_active komplett entfernt, durch is_public (Admin-Toggle) ersetzt
- Neues selected_api_key_id auf users-Tabelle
- AnthropicService: globaler _token entfernt, apiToken pro Request
- Token-Durchreichung: StreamChat → ProcessStream → RunAgentChat →
RunPreparer/RunReview/RunFinalizer, ExecuteTool, send_to_session
- ChatEndpoint: User-Key aus DB laden, an StreamChat übergeben
- TelegramService: Key per bot.UserId auflösen
- CronjobService: Key per job.UserId auflösen
- Neue Endpoints: GET /api/api-keys/available, PUT /api/api-keys/select/{keyId},
GET /api/api-keys/selected, PUT /api/admin/api-keys/{keyId}/public,
POST /api/admin/api-keys/check-all
- Program.cs: AnthropicService ohne Token-Parameter
Frontend:
- API-Keys-Page: Public-Toggle (Globe/Lock) statt Activate/Deactivate
- Alle prüfen Button für Batch-Key-Check
- Chat: Key-Auswahl für alle User (nicht nur Admin)
- Dummy-Badge wenn kein Key ausgewählt
- Fallback-Badge bei Key ohne Usage-Daten
- Key-Switch-Modal: apiGetAvailableKeys + apiSelectApiKey
- New tool: github_code_search (GitHub Code Search API with text-match fragments)
- Tool available when GitHubToken is configured in server settings
- Registered in AnthropicService + ChatService tool pipelines
- ToolService: SetHttpClientFactory() pattern for lazy DI resolution
- ScannedKeyRecord: type field (anthropic_oauth, anthropic_api, anthropic_unknown, unknown)
- DetectKeyType() based on key prefix
- DB migration: type column with default 'anthropic_oauth'
- Frontend: type label in scanned keys list
- AnthropicService: db/chatService/anthropicService/userId/telegramService auch im
RunAgentChat (Zeile 899) und ChatNonStreaming (Zeile 1105) ExecuteTool-Aufruf
durchreichen – Telegram-Flow nutzt ChatNonStreaming, hatte zuvor null-Parameter
- ChatService: FixOrphanedAskUserChoice → FixOrphanedToolUse ersetzt
Prüft gesamte History auf orphaned tool_use-Blöcke (nicht nur ask_user_choice am Ende)
Synthetische tool_results werden eingefügt um Anthropic API 400 zu verhindern
- ToolService: Debug-Logging für send_to_session nach /tmp/gott_send_to_session.log
- Neues Tool send_to_session: Agent kann Nachrichten in andere Sessions schicken
- Ziel-Session per ID oder Name (case-insensitive) auffindbar
- User-Message wird nicht in DB gespeichert (wie Cronjob) – keine Bubble im Frontend
- Nachricht wird als '[Nachricht von Agent "X"]' kontextualisiert injiziert
- Sicherheitscheck: Ziel-Session muss demselben User gehören, keine eigene Session
- Zirkuläre Abhängigkeit ChatService ↔ AnthropicService via SetChatService() gelöst
- tool-ui.js: Display-Name für send_to_session
- RemoteConnectionManager: Singleton-Service verwaltet WebSocket-Verbindungen
mit Command-Execution (Send/Receive mit Timeout + SemaphoreSlim-Locking)
- RemoteEndpoint: WebSocket-Endpoint /api/remote (auth-frei), REST-APIs für
Connections/Assign/Unassign, PowerShell-Script-Auslieferung mit dynamischer URL
- remote.ps1: PowerShell-Client für Windows – verbindet per WebSocket,
sendet Hostname/User/OS, empfängt und führt Befehle aus, Heartbeat
- remote_execute Tool: Neues Agent-Tool, nur verfügbar wenn Session eine
zugeordnete Remote-Verbindung hat, führt PowerShell-Befehle remote aus
- Frontend: Menüpunkt 'Remote-Verbindungen' im Chat-Dropdown, Modal zeigt
alle aktiven WebSocket-Verbindungen (Hostname, User, OS, Verbindungszeit),
Verbinden/Trennen-Buttons pro Verbindung und Session
- Auth: /api/remote und /remote.ps1 von Authentifizierung ausgenommen
Architektur: Windows-Client → WebSocket → GOTT-Server → Agent-Tool
Session-gebunden: Eine Verbindung wird einer Session zugeordnet
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
- Toggle-Button (🗺️) im Chat-Input-Bereich neben Explorer
- Plan-Modus wird per ChatRequest.planMode an Backend gesendet
- Backend: Write-Tools gefiltert (nur read_file, list_files, glob, grep,
todo_write, memory_*, ask_user_choice bleiben), System-Prompt-Block
ergänzt der Änderungen verbietet, tool_choice nie 'any' erzwungen
- ChainRecord.PlanMode: pro Chain gespeichert (informativ für History)
- Chain-Meta-Badge '📋 Plan-Modus' bei Plan-Chains
- Choice-Response erbt planMode vom vorherigen Chain
- CSS: .plan-mode-active Styling (Primary-Color Highlight)
- Placeholder wechselt zu 'Plannen...' wenn aktiv
- Plan-Modus wird bei Session-Wechsel zurückgesetzt
- Neues Feld AllowUserChoice (bool, default true) im AgentRecord
- DB-Migration: allow_user_choice Spalte mit DEFAULT 1
- Agent-Form: Checkbox 'Rückfragen erlauben' nach 'Tool-Nutzung erzwingen'
- ToolService.GetToolDefinitions: neuer Parameter includeUserChoice
- ask_user_choice Tool wird nur eingebunden wenn Agent es erlaubt
- Review-Agents und Non-Streaming (Cronjobs) erhalten nie ask_user_choice
- ChatEndpoint reicht Agent.AllowUserChoice an StreamChat durch
Neues Tool 'ask_user_choice' analog zum AskUserQuestion aus dem Claude Agent SDK.
Claude kann dem User Multiple-Choice-Fragen stellen, wenn es mehrere sinnvolle
Wege gibt. Der User wählt per Button, Claude arbeitet mit der Antwort weiter.
Backend:
- ToolService: ask_user_choice Tool-Definition (question + choices[2-5])
- AnthropicService/ProcessStream: Tool wird NICHT ausgeführt, sondern als
SSE-Event 'user_choice' an den Client gesendet. stopReason wird auf
'awaiting_user_choice' gesetzt (mit Guard gegen Überschreibung durch
message_delta)
- ChatEndpoint: Erkennung von Choice-Responses (choiceToolCallId + choiceResult),
tool_result wird in die korrekte Chain gespeichert (wo der tool_use liegt),
toolChoice wird auf 'auto' gesetzt damit Claude frei antworten kann
- ChatService: FindChainWithToolCall() zum Auffinden der richtigen Chain,
BuildHistoryFromDb() erweitert um Choice-Chain-Erkennung (wenn letzte Chain
leer/nur tool_result → vorletzte Chain vollständig rekonstruieren)
- ChatModels: ChatRequest um ChoiceToolCallId + ChoiceResult erweitert
Frontend:
- api.js: apiChatChoice() für Choice-Responses
- chat.js: handleStreamEvent() als shared Handler extrahiert (sendMessage +
handleChoiceClick nutzen denselben Code), handleChoiceClick() startet neuen
Stream nach Button-Klick
- ui.js: addChoiceBubble() (live/interaktiv) + addChoiceBubbleStatic() (History)
- history.js: Choice-Bubbles in _renderMessagesIntoFragment + renderMessages,
Voraus-Suche nach zugehörigem tool_result, unbeantwortet = klickbare Buttons
- chat.css: Styling für Choice-Bubbles (Primary-Color-Outline-Buttons, Hover,
Selected/Unselected States)
Robustheit:
- Backend-Fallback wenn Claude choices als String statt Array sendet
- Frontend-Guard: Array.isArray(choices) an allen 4 Render-Stellen
- Page-Refresh mit offener Choice → aktive Buttons werden korrekt gerendert
- SkillEndpoint: GET /api/skills/{slug}/output/{filename} for skill output files
- WorkspaceEndpoint: GET /api/workspace/raw for raw file serving (images)
- File-Explorer: Image preview for png/jpg/gif/webp/svg/bmp/ico
- Chat UI: Parse [Krea: filename] tags into clickable chips with image modal
- ToolService: Increase execute timeout from 30s to 180s for long-running skills
- Tools werden jetzt auch gesendet wenn kein Workspace aber useMemory=true
- GetToolDefinitions(includeFileTools, includeMemory) für granulare Steuerung
- File-Tools geben saubere Fehlermeldung wenn workspace null
- MemoryService: Verwaltet data/agents/{agentId}/ Verzeichnisse
- MEMORY.md als Haupt-Memory-File
- memory/ Unterordner für Tages-Logs und thematische Notizen
- Sandbox-Prüfung verhindert Zugriff außerhalb des Agent-Dirs
- Memory-Tools für den Agent:
- memory_read: Liest Memory-Dateien
- memory_write: Schreibt/überschreibt oder hängt an (append)
- memory_list: Listet alle Memory-Dateien auf
- SystemPromptBuilder: Memory-Abschnitt mit Regeln und aktuellem
MEMORY.md-Inhalt wird in den System-Prompt injiziert
- ToolService/AnthropicService: Memory-Tools werden automatisch
eingebunden wenn MemoryService und AgentId verfügbar sind
- TODO.md: Embedding-basierte Suche und Subagents als Features
- Session has workspace field (absolute path, optional)
- ToolService stateless, receives workspace per call
- No workspace = no tools sent to API
- Removed hardcoded workspace from Program.cs
- Workspace field in session edit form