Commit Graph
212 Commits
Author SHA1 Message Date
Meleki 0097ce69db Rename archive divider 2026-03-09 07:19:35 +01:00
Meleki 33934b2c4a refactor(frontend): dedupliziere JS-Code und fixe Bugs
- fix: _oldestLoadedMessageId → _oldestLoadedSortKey (chat.js, chat-page.js)
- move: formatTimestamp nach ui-helpers.js (war _formatTimestamp in msg-actions.js)
- move: _isReviewMessage nach ui-helpers.js (war in history.js)
- add: _getSubAgentMeta + _createSubAgentHeader in ui-helpers.js
- refactor: stream-ui.js + history.js nutzen _createSubAgentHeader
- refactor: flushText() Hilfsfunktion in _renderReviewGroup (history.js)
- refactor: shared-page.js nutzt _mergeConsecutiveAssistantTexts statt eigener Kopie
- refactor: _initCardMenu + _onCardMenuAction Helper in dashboard.js

-53 Zeilen netto
2026-03-09 07:17:54 +01:00
Meleki 42d366ea47 UI-Polish: Telegram-Bot-Page und Agent-Page aufgeräumt
- 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)
2026-03-09 06:59:03 +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 b0d8bef5ea feat: Public-Flag für Agents + verfügbare Agents/Bots Endpoints erweitert
- 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
2026-03-08 20:25:52 +01:00
Meleki ec73ccd71e Telegram Bots als eigenständige Entität mit eigener Page
- Neue Tabelle 'telegram_bots' (bot_id, name, bot_token, webhook_secret, is_public)
- Automatische Migration bestehender Session-Telegram-Configs in telegram_bots
- Sessions verweisen via telegram_bot_id auf Bot (mehrere Sessions pro Bot möglich)
- Webhook-URL: /api/telegram/webhook/{botId} statt {sessionId}
- Eigene Telegram-Bot-Page (wie Agent/Cronjob/Session) statt Modal
- Bot-Page: Name, Token, Secret, Webhook-Verwaltung (registrieren/status/entfernen), Löschen
- Dashboard: Telegram Bots Section mit Cards (Name, maskierter Token, Session-Count)
- Session-Page: Bot-Picker (wie Agent-Picker) statt Token-Input, Chat-ID readonly + Unlink-Button
- Public-Flag: Bot kann von anderen Usern in ihren Sessions ausgewählt werden
- Vereinfacht: 1 Session = max. 1 Telegram Chat, allowed_chat_ids entfällt
- /start zeigt Chat-ID an, /unlink entfernt (Unlink nur über Web-UI)
- Nachrichten-Routing: Bot + Chat-ID → Session Lookup
2026-03-08 19:27:05 +01:00
Meleki 3b7bdb7a20 feat: OpenClaw session import with sorted history
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
2026-03-08 17:32:32 +01:00
Meleki 1597c10a3c Review-Agent: [FEEDBACK]-Tag in Markdown ausblenden + Kommentar aktualisiert 2026-03-08 15:17:11 +01:00
Meleki 1fc6889ced Review-Agent: Default=Approved + vollständige Tool-Boxes für Sub-Agents
Backend:
- Review-Agent: Default = Approved (analog zum Preparer Default=Forward)
  Nur bei explizitem [FEEDBACK]-Tag wird Feedback zurückgespielt
  Verhindert Loop wenn Review-Agent bestätigt ohne [APPROVED]-Tag
- Neues SSE-Event {agentType}_tool_end für Sub-Agent Tool-Ergebnisse
  Sendet toolName, input, result, isError nach Tool-Ausführung

Frontend Streaming (stream-ui.js + chat.js):
- addReviewToolUse: Vollständige Tool-Box mit Loading-Spinner statt nur Name
- finishReviewToolBox: Befüllt Tool-Box nach tool_end mit Details (Pfad, Diff, Result)
- Event-Handler für preparer/review/finalizer_tool_end

Frontend History (history.js):
- _renderReviewGroup: Vollständige Tool-Boxes statt einfache Tool-Use-Indikatoren
- Tool-Result Look-Ahead für korrekte Zuordnung (toolCallId-Match)
- Web-Search-Sources in Review-Bubbles unterstützt
- Tool-Visibility-Filter (isToolVisible) auch für Sub-Agent-Tools

CSS:
- .review-tool-use → .review-tool-box (erbt normale Tool-Box-Styles)
2026-03-08 15:08:59 +01:00
Meleki 87bde0cbaf fix: Review/Preparer/Finalizer-Bubbles im History-Rendering korrekt gruppiert
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).
2026-03-08 00:04:58 +01:00
Meleki 9abb5fd217 fix: esc() Quote-Escaping für Attribut-Kontexte + cache_control für Sub-Agents/Telegram
- 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
2026-03-07 22:42:20 +01:00
Meleki e930268476 refactor(js): 4. Iteration – Card-Preview-Helper, Button-Loading, Stream-Events vereinfacht
Neue Helper:
- _renderCardPreview(): Gemeinsamer Helper für Agent/Session-Card-Vorschau
  (ersetzt renderAgentInCard + renderSessionSelectCard Duplikate)
- withButtonLoading(btn, text, fn): Eliminiert ~15x identisches
  disable/text/try/finally/reset Pattern in allen Pages
- formatDate(): Nach ui-helpers.js verschoben (war in dashboard.js)
- createMDE(): maxHeight-Option hinzugefügt

Dedupliziert:
- handleStreamEvent: 12 Preparer/Review/Finalizer cases → 7 durch
  case-Grouping (start/text/tool_use shared)
- _escCmdAttr() entfernt → nutzt jetzt esc() aus ui-helpers.js
- feInitEasyMDE() nutzt jetzt createMDE() statt eigener EasyMDE-Init

Betroffene Dateien: ui-helpers.js, chat.js, commands-ui.js,
file-explorer.js, dashboard.js, session-page.js, cronjob-page.js,
profile-page.js, admin-page.js, server-settings-page.js, settings-page.js
2026-03-07 22:34:37 +01:00
Meleki e4ccaf9dee refactor(js): dritte Refactoring-Iteration – weitere Duplikate eliminiert
Zusammengeführt/dedupliziert:
- renderMessages() nutzt jetzt _renderMessagesIntoFragment() statt eigenen switch/case
- addChoiceBubble() + addChoiceBubbleStatic() → _createChoiceBubble() Helper
- addErrorBubble() + addWarningBubble() → _addSystemBubble() Helper
- Chain-Meta-Erstellung (3x) → _createChainMetaDiv() Helper
- Agent-Picker-Setup (4x) → setupAgentPicker() Helper in session-page
- more-Click-Handler (2x) → initMoreButton() Helper in ui-helpers
- showLoginLinkModal() nutzt jetzt _createModal()
- showMessage() in server-settings → showToast()

Verwaiste Funktionen entfernt:
- addAssistantBubble(), addReviewBubbleStatic(), addChoiceBubbleStatic()
- addAttachmentIndicator(), addToolBoxStatic(), appendToolResult()
- serverSettingsMessage HTML-Element

Netto: -261 Zeilen
2026-03-07 21:58:36 +01:00
Meleki 1a2c407538 refactor(frontend): Duplikate in JS eliminieren – Runde 2
Neue Helper-Funktionen:
- _openCardMenu(trigger, dropdown): Card-Menü-Positionierung (4x in dashboard.js dedupliziert)
- _createModal(title, extraClasses): Modal-Boilerplate (3 Modals in modals.js dedupliziert)
- _openPickerModal(title, items, currentId, onSelect, opts): Picker-Modal (Agent + Session zusammengeführt)
- createMDE(element, opts): EasyMDE-Initialisierung (3x in agent/session/profile-page dedupliziert)

Weitere Bereinigungen:
- _formatReplyTimestamp() entfernt, durch _formatTimestamp() ersetzt (reply.js + chat.js)
- showFormMessage/showPageMessage in admin-page.js durch showToast() ersetzt
- Inline-Nachrichten (profileMessage, profilePasswordMessage, adminMessage, adminFormMessage) durch Toast-Notifications ersetzt, zugehörige HTML-Elemente entfernt
- profile-page.js: messageDiv/passwordMessageDiv-Logik durch showToast() ersetzt

11 Dateien, -210 Zeilen netto
2026-03-07 21:50:23 +01:00
Meleki b56b83ad1e Refactor: JavaScript-Code-Duplikate eliminiert (-227 Zeilen)
Neue Helper-Funktionen extrahiert:
- _runStream(): SSE-Stream-Loop aus sendMessage() + handleChoiceClick() (chat.js)
- _createMessageBubble() + _addBubbleActions(): Bubble-Erstellung aus 6+ Stellen (bubbles.js)
- createAttachmentIndicator(): Attachment-Anzeige aus bubbles/history/archive (bubbles.js)
- _renderMessagesIntoFragment(): Shared zwischen loadOlderMessages + loadLatestArchive (history.js)
- _isReviewMessage(): Review/Finalizer/Preparer-Check aus 8+ Stellen (history.js)
- _renderChoiceBubbleInFragment(): Choice-Bubble-Rendering extrahiert (history.js)
- _buildDiffLines(): Diff-Zeilen aus buildEditDiff + buildWritePreview (tool-ui.js)
- _buildAvatarTransformStyle(): Avatar-Transform aus buildSessionCard + buildAgentCard (cards.js)
2026-03-07 21:37:41 +01:00
Meleki 11acfde081 Dashboard-Performance: API-Endpoints konsolidieren
Backend:
- GET /api/sessions: Git-Status inline integriert (parallel pro Session)
  - Neue Hilfsmethoden GetGitStatusSummaryAsync (Counts) und
    GetGitStatusDetailedAsync (Dateinamen, für Einzel-Endpoint)
  - GetSessionsWithStats gibt typisierte SessionWithStats zurück
  - Neue Models: SessionWithStats, GitStatusSummary
- GET /api/agents: Skills inline pro Agent integriert
  - SkillService als Parameter in HandleList
  - Skills als Array mit slug/name/description

Frontend:
- Dashboard: 1 paralleler Promise.all statt sequentieller Requests
  - Vorher: agents → sessions → N×git-status → M×agent-skills → cronjobs → shares
  - Nachher: Promise.all([agents, sessions, cronjobs, shares]) (4 Requests)
  - Git-Status direkt aus Session-Response, Skills aus Agent-Response
- Session-Page: Agent-Skills aus inline-Daten statt N×apiGetAgentSkills

Reduziert Dashboard-Requests von ~4+N+M auf 4 (fix).
2026-03-07 19:40:26 +01:00
Meleki 0dcc05ebf9 refactor: ui.js, chat.js, history.js in 13 modulare Dateien aufteilen
Die monolithische ui.js (1534 Zeilen) zusammen mit chat.js (612) und
history.js (626) in fokussierte Module aufgeteilt:

Neue Dateien aus ui.js:
- ui-helpers.js (126) - DOM-Utilities, $, esc, truncate, scrollDown, Toast
- markdown.js (143) - renderMarkdown, wrapKreaGalleries, LaTeX/Code-Schutz
- cards.js (90) - buildSessionCard, buildAgentCard
- msg-actions.js (208) - Delete, Mark, Share, Reply-Button, Timestamp
- tool-ui.js (332) - Tool-Boxes, Diffs, Todo-Liste, Visibility
- modals.js (190) - System-Prompt, Command-Output, Krea-Image Modals
- stream-ui.js (124) - Stream-Bubble, Review-Streaming
- bubbles.js (312) - User/Assistant/Error/Warning/Choice/Review Bubbles

Neue Dateien aus chat.js:
- reply.js (54) - Reply/Quote-Handling mit pendingReply State
- files.js (110) - File-Upload, Workspace-Refs mit pendingFiles/Refs State

Neue Datei aus history.js:
- archive.js (173) - Archiv-Loading mit loadedArchiveCount State

Verbleibend:
- chat.js (448) - Stream-Events, sendMessage, handleChoiceClick, Plan-Mode
- history.js (464) - History laden, Polling, Message-Rendering

Kein Code verändert, nur verschoben. Alle 94 Funktionen verifiziert.
Globale Variablen in die Module verschoben, wo sie primär genutzt werden.
2026-03-07 19:32:33 +01:00
Meleki a82d8cfb05 Add missing message actions to archive messages
- 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
2026-03-07 18:53:45 +01:00
Meleki 4f027360fd feat: Anweisungen-Feld für Agents mit EasyMDE-Editor
- AgentRecord: TaskInstruction (string, nullable)
- DB-Migration: task_instruction TEXT Spalte
- AgentEndpoint: Create/Update lesen taskInstruction
- SystemPromptBuilder: '## Anweisungen' Block nach Soul, nur wenn nicht leer
- HTML: Textarea #agentTaskInstruction nach Rückfragen-Checkbox
- agent-page.js: EasyMDE-Editor mit Init, Laden, Speichern, Destroy
2026-03-07 17:20:38 +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 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 f12fbfdc3e Adjust background color of user message buttons and timestamp 2026-03-07 12:36:52 +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 1c11ffa3cd feat: Dashboard-Badge + System-Prompt-Hinweis für ask_user_choice
- Dashboard: 'Rückfragen'-Badge (🔵) bei Agent-Card wenn allowUserChoice aktiv
- SystemPromptBuilder: Hinweis-Block der Claude anweist, ask_user_choice sparsam zu nutzen
2026-03-07 11:45:06 +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 6c38ccfe12 Web-Search: Streaming-Fix (pauseStreamBubble statt resumeStreamBubble), leere Suchergebnisse nicht speichern, Sources auf Shared-Pages anzeigen 2026-03-07 10:46:45 +01:00
Meleki d81dab635a fix(web-search): Text-Bubbles nach Web-Search zu einer Bubble zusammenführen
- history.js: _mergeConsecutiveAssistantTexts überspringt web_search_result
  Messages beim Suchen des vorherigen Text-Blocks, sodass Text vor und
  nach einer Web-Search in der History als eine Bubble gerendert wird
- Text-Blöcke werden mit doppeltem Zeilenumbruch statt Leerzeichen
  zusammengefügt (besseres Markdown-Rendering)
- chat.css: web_search Tool-Box von Opacity-Regel ausgenommen
2026-03-07 10:06:23 +01:00
Meleki f64052caf4 feat: Web-Search Sources anzeigen (Streaming + History + Archive + Shared)
Backend:
- web_search_tool_result Sources extrahieren (url, title)
- Als 'web_search_result' Message-Typ in DB persistieren
- Sources im web_search_end SSE-Event mitsenden
- Alle 3 Chat-Pfade: StreamChat, RunAgentChat, ChatNonStreaming

Frontend:
- renderToolBoxContent: Sources-Sektion mit klickbaren Domain-Links
- finishToolBox/addToolBoxStatic: sources-Parameter durchgereicht
- History: web_search_result Message-Typ in allen 3 Render-Pfaden
- web_search immer sichtbar (auch bei 'modifications' Filter)

CSS:
- .web-search-sources: Flex-Wrap Container
- .web-search-source: Domain-Pill mit Hover-Effekt, Title-Ellipsis
2026-03-07 09:56:09 +01:00
Meleki 116f21105c fix(chat): Web-Search-Streaming – Text-Bubbles nach Search in gleicher Bubble fortsetzen
- chat.js: _afterWebSearch Flag trackt ob gerade eine Web-Search beendet wurde
  - text_start nach Web-Search: resumeStreamBubble() statt neue Bubble
  - web_search_start: Bubble NICHT beenden (bleibt finalisiert im DOM)
  - web_search_end: setzt _afterWebSearch=true
  - Flag wird bei tool_start, review_start, finalizer_start, error, done zurückgesetzt
- ui.js: Neue resumeStreamBubble() Funktion
  - _lastStreamDiv/_lastStreamText speichern letzte finalisierte Bubble
  - resumeStreamBubble() reaktiviert die letzte Bubble zum Weiter-Streamen
  - Verhindert separate Message-Blöcke bei mehrfachen Web-Searches
2026-03-07 09:48:14 +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 bfd78278ab feat: Servereinstellungen-Seite für Admins
- Neuer Endpoint GET/PUT /api/admin/server-settings
  - Liest appsettings.Production.json (Fallback: appsettings.json → Standardwert)
  - Schreibt immer in appsettings.Production.json
  - Definierte Settings: AnthropicToken, MaxIterations, PayloadLogging, PayloadLoggingGzip, KreaToken, KreaApiKey
- Neue Frontend-Seite 'server-settings' (Admin-only)
  - Dynamisches Formular basierend auf Setting-Definitionen vom Backend
  - Password-Felder mit Eye-Toggle, Checkboxen für Booleans, Number-Inputs
  - Hinweis dass Neustart erforderlich ist
- Dashboard: Neuer Link 'Servereinstellungen' für Admins
- appsettings.Production.json vom Publish ausgeschlossen (CopyToPublishDirectory=Never)
2026-03-06 22:32:33 +01:00
Meleki af2f821c72 Session-Form: Review-Agent in erweiterte Einstellungen verschoben 2026-03-06 21:22:21 +01:00
Meleki 4775b8ded7 feat: Avatar Position-Offset (translate X/Y)
Backend:
- AgentRecord + SessionRecord: AvatarOffsetX, AvatarOffsetY Properties
- DB-Migration: avatar_offset_x/y REAL DEFAULT 0 auf agents + sessions
- Agent/Session Endpoints: Create + Update lesen/schreiben Offset-Felder
- GetSessionsWithStats: Offset-Felder ans Frontend

Frontend:
- Avatar-Editor: X/Y Offset-Slider (-50% bis +50%) im Modal
  - buildTransformStyle() Helper für transform: scale() translate()
  - getOffsetX()/getOffsetY() Public API
  - Reset bei Clear/AI-Generate/Upload
- ui.js: buildAgentCard + buildSessionCard rendern transform mit Offset
- Agent-Page + Session-Page: initialOffsetX/Y + Save
- CSS: .av-offset-row Styles (gruppiert mit .av-scale-row)
2026-03-06 21:14:51 +01:00
Meleki 6369f7f09c Review-Nachrichten: konsistentes Styling in History, Chat und Shared-Links
- renderMarkdown: [Review: Agent], [Review-Feedback ...], [APPROVED] Tags parsen
  → styled HTML-Header bzw. ausgeblendet (zentral für alle Views)
- history.js: Review-Messages als .review-bubble rendern statt .assistant/.user
  Review-Messages vom Merging ausgenommen
- shared-page.js: Review-Messages erkennen → .review-bubble Klasse
  Merge-Logik schützt Review-Messages vor Zusammenführung
- addReviewBubbleStatic(): Neue Funktion für History-Rendering mit allen
  Buttons (Reply, Delete, Mark, Share)
- chat.css: .review-inline-header, .review-inline-feedback Styles
2026-03-06 17:31: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 40c8fee531 feat: zuverlässiger Stop-Button für Chat-Streaming
- StreamingTracker: CancellationTokenSource pro Session, Cancel()-Methode
- ChatEndpoint: POST /api/chat/stop Endpoint, linkedCts verknüpft
  Stop-Token mit Client-Disconnect-Token
- AnthropicService: cancellationToken an ExecuteTool durchgereicht
- ToolService: CancellationToken-Parameter, execute-Tool verknüpft
  externen Token mit 180s-Timeout, killt Prozess bei Abbruch
- Frontend: apiStopChat() + stopStreaming() ruft Backend-Stop auf
2026-03-06 15:44:08 +01:00
Meleki 1f5f49228b fix: Krea-Bild-URLs auf /api/images/file/ korrigieren, Thumbnail-Endpoint hinzufügen
- ui.js: [Krea: datei] URLs von /api/skills/krea-api/output/ auf /api/images/file/ geändert
- KreaEndpoint: GET /api/images/file/{filename}/thumb mit gecachten WebP-Thumbnails (320px)
- Thumbnail-Cache in data/cache/images/, analog zum SkillEndpoint
2026-03-06 15:10:26 +01:00
Meleki 1b9cc29421 Admin: Login-Link mit window.location.origin statt Server-Host
- Backend gibt nur Token zurück statt fertigen Link
- Frontend baut Link via window.location.origin zusammen
- Zeigt korrekte Domain/Port statt internes http://127.0.0.1

Backend:
- AdminEndpoint: POST /api/admin/users/{userId}/login-link gibt { token }
- AuthEndpoint: GET /api/auth/autologin?token=xxx setzt Cookie + redirect
- AuthMiddleware: autologin-Route von Auth ausgenommen

Frontend:
- api.js: apiAdminGetLoginLink() Funktion
- admin-page.js: Login-as-User Button → Login-Link Button mit Modal
- form.css: Styling für Login-Link Modal
2026-03-06 14:35:01 +01:00
Meleki eeecd3da62 cleanup: lokale escapeHtml/esc Duplikate entfernt, globale esc() aus ui.js verwenden 2026-03-06 14:24:20 +01:00
Meleki e45498ac50 Session-Cards: buildSessionCard() Helper + Picker-Modal für Cronjob-Formular
- buildSessionCard(session, agent) Helper in ui.js (analog zu buildAgentCard)
  Erzeugt .card mit Avatar, Name, Badges (Agent, Kontext, Telegram) und Meta (Nachrichten, Archiv, Workspace)
- Dashboard refactored: Session-Cards nutzen buildSessionCard() statt inline HTML
- Cronjob-Formular: <select> für Session und Benachrichtigungs-Session durch
  klickbare Session-Cards + Picker-Modal ersetzt
- openSessionPickerModal() mit filterWithAgent-Option (Session-Dropdown nur
  Sessions mit Agent, Notify-Dropdown alle Sessions)
- CSS: .session-select-card und .session-select-change Klassen analog zu agent-*
2026-03-06 14:05:32 +01:00
Meleki 92c20402eb refactor: Agent-Auswahl in Session-Form als Card + Picker-Modal
- buildAgentCard() Helper in ui.js erstellt (wiederverwendbar für Dashboard + Picker)
- Session-Form: select-Dropdown durch klickbare Agent-Card ersetzt
- Agent-Picker-Modal zeigt alle Agents mit identischen Cards wie am Dashboard
- Dashboard refactored: nutzt buildAgentCard() statt dupliziertem Inline-HTML
- Kein duplizierter Code mehr für Agent-Card-Rendering (Badges, Skills, Avatar)
2026-03-06 14:01:27 +01:00
Meleki 011b26c37f feat(telegram): Zugriffskontrolle mit Chat-ID-Whitelist
- TelegramService: IsChatIdAllowed() prüft Owner + Whitelist
- /start von unbekannter ChatId: Zugriff verweigert + ChatId angezeigt
- Owner wird bei Zugriffsanfrage benachrichtigt (Username + ChatId)
- Alle Commands/Messages prüfen Whitelist vor Verarbeitung
- Neues Feld telegram_allowed_chat_ids in sessions-Tabelle
- Frontend: Input für erlaubte Chat-IDs in Session-Telegram-Settings
- API: allowedChatIds in Save/Get durchgereicht
2026-03-06 13:04:02 +01:00
Meleki 5661e55898 style(mobile): shared-content padding for mobile view 2026-03-06 12:40:20 +01:00
Meleki 34cecd03a1 refactor: Avatar-Editor als wiederverwendbares Modal-Modul
- Neues avatar-editor.js: Upload, Paste, AI-Generate, Scale, Clear in einem Modal
- Session + Agent Pages: ~280 Zeilen doppelter Avatar-Code → je 5 Zeilen AvatarEditor.init/destroy
- Avatar-Preview klickbar → öffnet Modal mit allen Einstellungen
- chat.css: Shared-Content Message-Styling (max-width, border)
2026-03-06 11:55:00 +01:00
Meleki 057d37d76f feat: Avatar Scale (0.5×–3×) + Krea AI Bildgenerierung für Avatare
Backend:
- SessionRecord + AgentRecord: neues Feld AvatarScale (double, Default 1.0)
- DatabaseService: avatar_scale Migration, in Create/Update/GetWithStats
- SessionEndpoint + AgentEndpoint: avatarScale in Create/Update
- api.js: apiKreaStatus(), apiKreaGenerate()

Frontend:
- Session + Agent Templates: Range-Slider (0.5×–3×) in Avatar-Section
- Krea AI Generate: Prompt-Input + Magic-Button (nur wenn KreaToken konfiguriert)
- Live-Preview: transform: scale() auf Avatar-Vorschau
- Dashboard: scale() auf Session- und Agent-Card-Images
- form.css: avatar-scale-row + avatar-ai-section Styling
2026-03-06 10:59:09 +01:00
Meleki 4ebbeaa818 feat: shared-page message merging + UI reorganization
Shared Page:
- Merge consecutive assistant text messages (same iteration)
- Add iteration field to thread API response
- Unified rendering for single/thread messages

UI Reorganization (manual changes):
- Session + Agent forms: collapsible 'Weitere Einstellungen' section
- Agent defaults: tool_choice unchecked, web_search 2025, model opus-4-6
- Profile: default-path field hidden, divider removed
- Form spacing adjustments, .more toggle style
2026-03-06 08:52:27 +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 8e7bda50f9 feat: Ordner erstellen/löschen im File Explorer
Backend (WorkspaceEndpoint.cs):
- POST /api/workspace/mkdir – Ordner im Session-Workspace erstellen
- DELETE /api/workspace/dir – Leeren Ordner im Session-Workspace löschen
- POST /api/workspace/agent/mkdir – Ordner im Agent-Memory erstellen
- DELETE /api/workspace/agent/dir – Leeren Ordner im Agent-Memory löschen
- POST /api/workspace/browse/mkdir – Ordner im Folder-Browser erstellen
- Sicherheit: Path-Traversal-Schutz, Root nicht löschbar, nicht-leer → 409

Frontend (file-explorer.js):
- 📁+ Button im Header für neuen Ordner (File Explorer + Folder Browser)
- 🗑️ Button bei jedem Ordner (erscheint on hover, nur File Explorer)
- Validierung: ungültige Zeichen werden abgelehnt

CSS:
- base.css: Icon-Button mit zwei Icons (folder + plus)
- file-explorer.css: Ordner-Zeile als Flex (Label + Delete-Button)
2026-03-05 21:01:09 +01:00