Commit Graph
27 Commits
Author SHA1 Message Date
Meleki 10da2bd964 feat: Remote-Verbindungen – Windows-Workstations per WebSocket steuern
- 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
2026-03-11 07:04:24 +01:00
Meleki 9f4746c2e7 fix: fullChainStartIndex erkennt awaiting_user_choice der vorherigen Chain
Bug: Nach ask_user_choice wurde die vorherige Chain (mit allen tool_use/
tool_result Paaren) nur als Text geladen statt vollständig. Die API bekam
tool_use IDs ohne zugehörige tool_result Blöcke → 400 Error.

Ursache: Die fullChainStartIndex-Logik prüfte nur ob die AKTUELLE Chain
eine tool_result mit Iteration 999 hat. Aber die Choice-Antwort wird in
die VORHERIGE Chain gespeichert (ChatEndpoint Zeile 68-78), nicht in die
aktuelle. Deshalb wurde needsPrevious=false → vorherige Chain nur als Text.

Fix: Dritte Prüfung hinzugefügt - wenn die vorherige Chain mit
stop_reason='awaiting_user_choice' endete, muss sie vollständig geladen
werden (sie enthält den tool_use UND den tool_result für die Choice).
2026-03-10 22:29:40 +01:00
Meleki 8dd962ac49 fix: CleanOrphanedWebSearchBlocks bidirektional – entfernt auch verwaiste web_search_tool_result ohne server_tool_use
Vorher wurden nur orphaned server_tool_use entfernt (die keinen
web_search_tool_result hatten). Jetzt auch umgekehrt: web_search_tool_result
Blöcke ohne zugehörigen server_tool_use werden entfernt.

Mögliche Ursache für API 400 'web_search_tool_result without corresponding
server_tool_use': Parse-Fehler beim Laden des server_tool_use aus der DB
oder Reihenfolgeprobleme führten dazu, dass nur der Result-Block in der
History landete.
2026-03-10 11:49:08 +01:00
Meleki 3153cb6c6b fix: web_search_tool_result als Raw-JSON speichern für History-Rebuild
Problem: API 400 'web_search tool use without corresponding
web_search_tool_result block' – weil web_search_tool_result nur als
Sources-Array gespeichert wurde und in BuildHistoryFromDb kein Handler
dafür existierte. Der server_tool_use-Block war in der History, aber
der zugehörige web_search_tool_result fehlte.

Backend (AnthropicService):
- 3 Speicher-Stellen (StreamChat, RunAgentChat, ChatNonStreaming):
  Raw-JSON statt ExtractWebSearchSources-Array speichern

Backend (ChatService):
- Neuer Handler für web_search_result in BuildHistoryFromDb:
  Raw-JSON als web_search_tool_result in assistant content einfügen
- Rückwärtskompatibilität: Alte Array-Einträge überspringen
- CleanOrphanedWebSearchBlocks(): Post-Processing entfernt
  orphaned server_tool_use mit name web_search (alte DB-Einträge)

Frontend (history.js, shared-page.js):
- _extractWebSearchSources(): Unterstützt altes Array-Format und
  neues Raw-JSON Format (content[].type === web_search_result)
2026-03-10 11:34:43 +01:00
Meleki dd99216913 fix: SSE-Stream-Stabilität und History-Trimming tool_use/tool_result-Schutz
- Kestrel MinResponseDataRate per-Request deaktivieren für SSE-Streams
  (Default 240 bytes/s + 5s Grace → client_disconnected bei langen Tools)
- SSE-Heartbeat alle 15s während Stream (schützt gegen Browser/Netzwerk-Idle)
- History-Trimming: RemoveRange schneidet nicht mehr in tool_use/tool_result-Paare
- Reminder-Insertion: kein Einfügen zwischen tool_use und tool_result
2026-03-09 20:13:22 +01:00
Meleki 1e7b68fb09 Fix: ask_user_choice Dauerschleife bei mehreren aufeinanderfolgenden Choice-Runden
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.
2026-03-09 19:44:07 +01:00
Meleki fb9ff23ad4 fix: server_tool_use/result (bash_code_execution) korrekt verarbeiten
- 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
2026-03-09 11:52:58 +01:00
Meleki 5d090e160b feat: Windows-Kompatibilität
- WorkspaceHelper: Zentrale Hilfsmethoden (IsWindows, TempDir, IsSubPathOf,
  GetRelativePath, ShellExecutable, ShellArguments)
- ToolService: execute nutzt cmd.exe auf Windows, GetRelativePath mit
  Forward-Slashes, IsSubPathOf für case-insensitive Pfadprüfung
- SessionEndpoint: /tmp → Path.GetTempPath(), bash → cmd.exe,
  Fire-and-forget via .bat statt systemd-run auf Windows
- ChatService: /tmp → WorkspaceHelper.TempDir
- MemoryService: IsSubPathOf + GetRelativePath
- WorkspaceEndpoint: HandleBrowse zeigt Laufwerke auf Windows,
  IsSubPathOf statt StartsWith
- InfoEndpoint: gott.exe auf Windows, isWindows-Flag in API-Response
- Frontend: File-Explorer mit Laufwerks-Navigation auf Windows
2026-03-09 11:35:04 +01:00
Meleki cdad7faad4 fix: tool_end SSE-Event nicht mehr auf 500 Zeichen kürzen + tool_result History-Truncation
- 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
2026-03-09 09:40:30 +01:00
Meleki dcedbaa074 refactor: Backend deduplizieren – 13 Dateien, -528 Zeilen netto
ChatContext: 3 identische Context-Klassen (PreparerContext, ReviewContext,
FinalizerContext) zu einer SubAgentContext-Klasse zusammengefasst.

ChatService: 3x40 Zeilen Sub-Agent-Setup durch BuildSubAgentContext() ersetzt.

AnthropicService: 5 Hilfsmethoden extrahiert – ExtractWebSearchSources(),
TruncateToolResult(), AddToolsToPayload(), ParseServerToolUse(), TrackUsage().

WorkspaceEndpoint: 5 Session/Agent-Endpoint-Paare durch generische Core-Handler
mit basePath-Parameter ersetzt. Ungenutzte rmdir-Endpoints entfernt.

AgentEndpoint: Doppeltes Agent-DTO-Mapping durch MapAgentList() ersetzt.

SessionEndpoint: Doppelte Session/Agent-Auflösung durch ResolvePromptContext() ersetzt.

DatabaseService: Toten Code entfernt (SetSessionTelegramChatId,
ClearSessionTelegramChatId, GetSessions, GetUserSessions). ConvertDataUrlToWebP
und ResizeDataUrlToWebP zu einer Methode zusammengefasst.

TelegramEndpoint: Bot-DTO-Mapping durch MapBotResponse() dedupliziert.

KreaEndpoint + SkillEndpoint: Thumbnail-Generierung in ImageService.GenerateThumbnail()
extrahiert, SixLabors-Imports aus Endpoints entfernt.

CronjobEndpoint: 7x ctx.Items[UserId] durch ctx.GetUserId() ersetzt.
2026-03-09 09:18:49 +01:00
Meleki 57560cbbea refactor: MaxHistory + ReminderInterval in appsettings auslagern
- 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
2026-03-09 07:03:47 +01:00
Meleki 8357bc66c5 "Understood." übersetzt auf "Verstanden." 2026-03-09 06:50:06 +01:00
Meleki 47d6f44e07 Auto-Reminder alle 30 Messages + History-Limit 120
- 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
2026-03-09 06:35:35 +01:00
Meleki 83945689a6 Remove tool_choice agent option - auto-detect based on workspace/skills/memory
- 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
2026-03-09 05:39:09 +01:00
Meleki bed4b1687e fix: openclaw-import Messages aus LLM-History nicht mehr ausfiltern
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.
2026-03-08 20:41:32 +01:00
Meleki 14e721f95b fix(preparer): Logik invertiert - Default=Forward, [QUESTION]=Stopp
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
2026-03-07 16:35:29 +01:00
Meleki 43d3e9dc26 fix: Tag-Feld für Sub-Agent-Messages – verhindert API 400 bei tool_use ohne tool_result
- 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.
2026-03-07 15:37:28 +01:00
Meleki 494f431963 feat: Vorbereiter-Agent (Preparer) für Sessions
- 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)
2026-03-07 15:23:22 +01:00
Meleki 8e0ae90dc6 Plan-Modus: System-Prompt-Blöcke kontextabhängig anpassen
- SystemPromptBuilder.BuildBlocks/Build bekommt planMode-Parameter
- Im Plan-Modus: Tools-Block zeigt nur Read-only-Tools (read_file, list_files, glob, grep)
- Im Plan-Modus: KRITISCH, Verhalten, Erinnerung und Git-Blöcke werden übersprungen
- Im Plan-Modus: Skills als 'nicht ausführbar' markiert
- Plan-Modus-Block zentral im SystemPromptBuilder statt doppelt in AnthropicService + SessionEndpoint
- ChatService reicht planMode an SystemPromptBuilder durch
- SessionEndpoint reicht planMode Query-Parameter an BuildBlocks durch
- System-Prompt-Modal zeigt korrekte Blöcke je nach Plan-Modus-Status
2026-03-07 12:20:44 +01:00
Meleki 6d95f9aec2 feat: Plan-Modus – Toggle im Chat zum Umschalten zwischen Plan/Ausführung
- 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
2026-03-07 12:07:39 +01:00
Meleki 89ceb61948 feat: Agent-Einstellung 'Rückfragen erlauben' (allowUserChoice)
- 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
2026-03-07 11:36:02 +01:00
Meleki 5f3e308975 feat: ask_user_choice Tool – interaktive Auswahlmöglichkeiten im Chat
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
2026-03-07 11:30:55 +01:00
Meleki 4bec740765 feat: Finalizer-Agent – dritter Agent der nach Worker + Review einschreitet
Backend:
- SessionRecord + DB-Migration: finalizer_agent_id auf sessions
- ChatContext.FinalizerContext (Model, SystemPrompt, Tools, Workspace)
- ChatService: FinalizerContext aufbauen (analog zu ReviewContext)
- AnthropicService: RunFinalizer() nach Review-Phase (oder direkt nach Worker)
- RunReviewAgentChat() refactored zu generischem RunAgentChat()
  mit agentType-Parameter ('review' | 'finalizer') für SSE-Events und DB-Tags
- SSE-Events: finalizer_start, finalizer_text, finalizer_tool_use, finalizer_done

Frontend:
- Session-Page: Finalizer-Agent-Picker (im 'Weitere Einstellungen' Bereich)
- Chat: SSE-Events für Finalizer-Phase verarbeiten
- UI: addReviewBubble/finalizeReviewBubble unterstützen agentType 'finalizer'
  mit eigener Farbe (success-green) und Flag-Checkered-Icon
- renderMarkdown: [Finalizer: AgentName] Tags parsen
- History: Finalizer-Messages als .finalizer-bubble rendern
- Shared-Page: Finalizer-Messages korrekt erkennen und stylen
- Dashboard: Finalizer-Badge (flag-checkered) auf Session-Cards
2026-03-06 23:35:30 +01:00
Meleki 5fe3f8ac87 feat: Review-Agent (Multi-Agent-Kommunikation)
- Session hat optionalen ReviewAgentId + MaxReviewIterations
- Nach end_turn des Worker-Agents wird der Review-Agent aufgerufen
- Review-Agent bekommt Worker-Konversation als Kontext + kann Tools nutzen
- [APPROVED] in Review-Antwort → fertig, sonst Feedback an Worker
- Worker korrigiert und wird erneut reviewed (max N Runden)
- SSE-Events: review_start, review_text, review_tool_use, review_feedback, review_approved
- Chat-UI: Review-Phase als eigene Bubble mit Header, Text, Status
- Session-Page: Review-Agent-Picker (gleicher Agent-Card-Helper)
- Dashboard: Review-Agent-Badge auf Session-Cards
- DB-Migration: review_agent_id, max_review_iterations auf sessions
2026-03-06 16:04:00 +01:00
Meleki 4e1ed81f37 feat: DefaultPath als Base-Path für User-Workspaces
- WorkspaceHelper.cs: Zentrale Workspace-Auflösung (relativ → absolut)
- Session-Workspace wird relativ zum User-DefaultPath gespeichert
- System-Prompt bekommt aufgelösten absoluten Pfad
- Path-Traversal-Schutz: '..' in Workspace-Pfaden blockiert
- Browse-API gibt '..' nicht mehr als Eintrag zurück
- Folder-Browser: basePath-Limit, Back-Button navigiert zum Parent
- DefaultPath nur durch Admin bearbeitbar (Profil: readonly)
- Legacy: Absolute Pfade in session.Workspace weiterhin kompatibel
2026-03-05 22:49:09 +01:00
Meleki 8fc29c82d9 refactor: Chat-Payload vereinfacht + Inline-Bilder statt Platzhalter
Backend:
- ChatEndpoint empfängt nur noch content + sessionId (nicht mehr die gesamte History)
- History wird komplett aus DB aufgebaut via BuildHistoryFromDb
- Gelöschte Nachrichten (deleted_on) werden aus History gefiltert
- Leere Nachrichten werden übersprungen (kein API 400 mehr)
- BuildHistoryFromDb optimiert: nur Text für ältere Chains, Tool-Calls nur für aktuelle Chain
- GetChainMessages: includeDeleted-Parameter (Default: false)
- Archiv-Export nutzt includeDeleted: true

Frontend:
- messages[]-Array komplett entfernt (kein Client-seitiger History-State mehr)
- apiChat() sendet nur content + sessionId
- Inline-Bilder: [Bild: name] wird durch <img> ersetzt (live mit DataURL, History per API-Nachladen)
- _autoLoadImageAttachments() für History/Archiv/ältere Nachrichten
- Klick auf Inline-Bild öffnet Vollbild-Modal
2026-03-04 14:29:33 +01:00
Meleki 0120bb8f73 Telegram: Bot=Session statt User-Level, Chat-Code-Refactoring
- Telegram-Config (Bot-Token, Webhook-Secret, ChatId) von User-Settings
  in sessions-Tabelle verschoben → jede Session hat ihren eigenen Bot
- Link-Code-System komplett entfernt (TelegramLinkRecord gelöscht)
- /start verknüpft automatisch, kein /link mehr nötig
- Alle Endpoints session-basiert: /api/sessions/{id}/telegram/*
- Webhook-URL pro Session: /api/telegram/webhook/{sessionId}

Refactoring: Doppelten Chat-Code eliminiert
- Neuer ChatService: PrepareContext, BuildHistoryFromDb, ResolveModelId
- Neues ChatContext-Model als gemeinsame Datenstruktur
- AnthropicService.ChatNonStreaming() für Telegram (statt eigenem Loop)
- TelegramService um ~180 Zeilen reduziert, kein eigener Claude-Loop mehr
- ChatEndpoint nutzt ChatService.PrepareContext() statt eigener Setup-Logik
- Model-Mapping nur noch an einer Stelle (3x → 1x)

Frontend
- Telegram-Section von Settings-Page in Session-Bearbeitungsseite verschoben
- Webhook-Secret readonly, wird einmalig generiert und persistent gespeichert
- Status wird automatisch geladen, Register/Delete je nach Webhook-Status
- Toast-Notification-System (showToast) in ui.js
- Link-Code-Modal und Telegram-Menüpunkt im Dashboard entfernt
- Telegram-Badge auf Session-Cards (konfiguriert/verbunden)

Bugfix: Bearer statt x-api-key für OAuth-Tokens im TelegramService
2026-03-03 21:46:59 +01:00