diff --git a/Services/SystemPromptBuilder.cs b/Services/SystemPromptBuilder.cs index 6d3e735..5b67546 100644 --- a/Services/SystemPromptBuilder.cs +++ b/Services/SystemPromptBuilder.cs @@ -147,27 +147,44 @@ Wenn der User auf eine bestimmte Zeile in einer Datei verweist (z.B. `[Datei: fo blocks.Add(new PromptBlock { Icon = "fa-database", Label = "Agent · Memory (UseMemory)", Content = string.Join("\n", memoryLines) }); } - if (toolAny && !string.IsNullOrWhiteSpace(session.Workspace)) + // Git-Commit-Verhalten: relevant sobald Workspace vorhanden (unabhängig von ToolChoice) + if (!string.IsNullOrWhiteSpace(session.Workspace)) { - var verhaltensRegeln = new List - { - "## Verhalten", - "- Wenn du Dateien lesen, schreiben, bearbeiten, erstellen oder löschen willst: IMMER das entsprechende Tool aufrufen. NIEMALS den Inhalt nur in die Antwort schreiben.", - "- Wenn du Shell-Befehle ausführen willst: IMMER das execute-Tool verwenden.", - @"- Behaupte NIEMALS etwas getan zu haben (Datei geschrieben, Commit gemacht, Befehl ausgeführt) ohne das entsprechende Tool tatsächlich aufgerufen zu haben. Wenn kein Tool-Aufruf stattgefunden hat, ist nichts passiert.", - "- Plane nicht nur - handle sofort über Tool-Aufrufe." - }; - if (agent.AutoCommit) { - verhaltensRegeln.Add(@"- Nach jeder abgeschlossenen Änderung MUSS ein Git-Commit erstellt werden. Prüfe Änderungen mit `git diff`, erstelle einen passenden Commit mit einer aussagekräftigen Message. Mehrere zusammenhängende Änderungen dürfen in einem Commit zusammengefasst werden."); + blocks.Add(new PromptBlock + { + Icon = "fa-code-branch", + Label = "Agent · Git-Verhalten (Workspace + AutoCommit)", + Content = "## Git-Commits\n- Nach jeder abgeschlossenen Änderung MUSS ein Git-Commit erstellt werden. Prüfe Änderungen mit `git diff`, erstelle einen passenden Commit mit einer aussagekräftigen Message. Mehrere zusammenhängende Änderungen dürfen in einem Commit zusammengefasst werden." + }); } else { - verhaltensRegeln.Add(@"- Git-Commits NIEMALS eigenständig erstellen. Commits werden NUR durchgeführt wenn der User es EXPLIZIT anfordert (z.B. ""erstelle einen Commit"", ""commit""). Auch nach abgeschlossenen Aufgaben NICHT automatisch committen."); + blocks.Add(new PromptBlock + { + Icon = "fa-code-branch", + Label = "Agent · Git-Verhalten (Workspace)", + Content = "## Git-Commits\n- Git-Commits NIEMALS eigenständig erstellen. Commits werden NUR durchgeführt wenn der User es EXPLIZIT anfordert (z.B. \"erstelle einen Commit\", \"commit\"). Auch nach abgeschlossenen Aufgaben NICHT automatisch committen." + }); } + } - blocks.Add(new PromptBlock { Icon = "fa-cog", Label = "Agent · Verhalten (Workspace + ToolChoice: any" + (agent.AutoCommit ? ", AutoCommit" : "") + ")", Content = string.Join("\n", verhaltensRegeln) }); + if (toolAny && !string.IsNullOrWhiteSpace(session.Workspace)) + { + blocks.Add(new PromptBlock + { + Icon = "fa-cog", + Label = "Agent · Verhalten (Workspace + ToolChoice: any)", + Content = string.Join("\n", new[] + { + "## Verhalten", + "- Wenn du Dateien lesen, schreiben, bearbeiten, erstellen oder löschen willst: IMMER das entsprechende Tool aufrufen. NIEMALS den Inhalt nur in die Antwort schreiben.", + "- Wenn du Shell-Befehle ausführen willst: IMMER das execute-Tool verwenden.", + "- Behaupte NIEMALS etwas getan zu haben (Datei geschrieben, Commit gemacht, Befehl ausgeführt) ohne das entsprechende Tool tatsächlich aufgerufen zu haben. Wenn kein Tool-Aufruf stattgefunden hat, ist nichts passiert.", + "- Plane nicht nur - handle sofort über Tool-Aufrufe." + }) + }); blocks.Add(new PromptBlock { diff --git a/TODO.md b/TODO.md index 16fb6b7..0ad0047 100644 --- a/TODO.md +++ b/TODO.md @@ -9,7 +9,9 @@ - [ ] User-Management: Tabelle in Datenbank mit username / password. Wenn kein User vorhanden: dann admin mit password "admin" anlegen - [ ] Neuer Message-Tag: `[canvas::<height (optional)>]...[/canvas]` - [ ] Websearch Tool? -- [ ] Anfrage/Stream abbrechen +- [x] Anfrage/Stream abbrechen +- [ ] Telegram Intergration +- [ ] Refactoring: Agent/Session-Einstellungen, die den System-Prompt bzw. das Tool Use bearbeiten ## Bugs - [x] Wenn gerade gestreamt wird und man refreshed die Seite, dann verliert das Frontend den Status "Streaming..." und ich kann eine Nachricht schreiben, obwohl das nicht möglich sein sollte @@ -20,10 +22,11 @@ ## Frontend - [x] Chat: Es scrollt beim Laden nicht ganz nach unten, ich denke weil im DOM noch etwas nachgeladen wird (ich denke es ist die Schriftart), und die Höhe sich beim Laden nochmal verändert -- [x] Chat: User-Nachrichten mit dem Tag [Datei: pfat/zur/datei.xyz:1-10] wird nicht als HTML geparsed +- [x] Chat: User-Nachrichten mit dem Tag [Datei: pfad/zur/datei.xyz:1-10] wird nicht als HTML geparsed - [x] Chat: Wird zwar erkannt und ist klickbar, aber es öffnet sich einfach nur der File Explorer, ohne dass sich die Datei öffnet und die Darstellung in Monospace ist auch nicht schön - [x] Chat: Es werden momentan alle Tool-Calls angezeigt - die Anzeige soll individuell in den Einstellungen gemacht werden können. Auswahl aus drei Stufen: "Alle anzeigen" / "Nur Modifikationen" (file änderungen, memory änderungen, etc.) / "Verstecken" - [ ] Browser: "Zurück"-Taste soll auf den vorherigen location.hash wechseln +- [ ] File Explorer: CodeMirror lässt sich horizontal nicht scroll ## Ideas / Backlog - [ ] Memory: Embedding-Modell für semantische Suche über Memory-Dateien (Vektor-basiert + BM25 Hybrid Search) diff --git a/wwwroot/css/chat.css b/wwwroot/css/chat.css index 8eef8e8..f294a6a 100644 --- a/wwwroot/css/chat.css +++ b/wwwroot/css/chat.css @@ -534,7 +534,7 @@ border-radius: var(--border-radius); overflow: hidden; width: 90vw; - max-width: 700px; + max-width: var(--modal-width); max-height: 80vh; display: flex; flex-direction: column; @@ -592,7 +592,7 @@ /* Command Output Modal */ .cmd-output-modal { - max-width: 800px; + max-width: var(--modal-width); } .cmd-output-meta { @@ -671,15 +671,16 @@ /* Krea Image Modal */ .krea-modal { + width: max-content; max-width: 90vw; - max-height: 90vh; + max-height: unset; } .krea-modal-body { display: flex; align-items: center; justify-content: center; - padding: var(--box-spacing); + padding: var(--badge-spacing); } .krea-modal-image { diff --git a/wwwroot/css/file-explorer.css b/wwwroot/css/file-explorer.css index a0706c0..244e5f9 100644 --- a/wwwroot/css/file-explorer.css +++ b/wwwroot/css/file-explorer.css @@ -16,7 +16,6 @@ border-radius: var(--border-radius); overflow: hidden; width: 90vw; - max-width: 1100px; height: 80vh; display: flex; flex-direction: column; @@ -60,6 +59,7 @@ overflow-y: auto; background: var(--f1-bg); flex-shrink: 0; + padding-block: var(--box-spacing); } .fe-sidebar-full { diff --git a/wwwroot/css/theme.css b/wwwroot/css/theme.css index f0ec73c..079b3fd 100644 --- a/wwwroot/css/theme.css +++ b/wwwroot/css/theme.css @@ -24,11 +24,12 @@ --box-padding: .75em 1em; --box-spacing: 1.5em; --input-padding: .45em .7em; - --button-padding: .45em .8em; + --button-padding: .5em .9em; --badge-padding: .2em .6em; --badge-spacing: .5em; --menu-item-padding: .5em .75em; --page-width: 900px; --hover-filter: contrast(.9); --transition-duration: .15s; + --modal-width: 700px; } diff --git a/wwwroot/js/ui.js b/wwwroot/js/ui.js index 83e0192..5181daf 100644 --- a/wwwroot/js/ui.js +++ b/wwwroot/js/ui.js @@ -11,6 +11,12 @@ marked.setOptions({ breaks: true, gfm: true }); function renderMarkdown(text) { if (!text) return ''; var html = marked.parse(text.trim()); + // Code-Blöcke (<pre>...<code>...</code>...</pre> und inline <code>...</code>) schützen + var codeBlocks = []; + html = html.replace(/<pre[\s>][\s\S]*?<\/pre>|<code[\s>][\s\S]*?<\/code>/gi, function(m) { + codeBlocks.push(m); + return '%%CODE' + (codeBlocks.length - 1) + '%%'; + }); // [Krea: dateiname.png] → Inline-Thumbnail mit Klick für Vollbild html = html.replace(/\[Krea:\s*([^\]]+)\]/g, function(match, filename) { var fn = filename.trim(); @@ -21,6 +27,10 @@ function renderMarkdown(text) { + '<img class="krea-thumb" src="' + thumbUrl + '" alt="' + safeFn + '" loading="lazy">' + '</span>'; }); + // Code-Blöcke wiederherstellen + html = html.replace(/%%CODE(\d+)%%/g, function(m, idx) { + return codeBlocks[parseInt(idx)]; + }); return html; }