feat: Auto-Context im Frontend anzeigen und in DB persistieren

- recalled_context-Header verstärkt (klare Nutzungs-Anweisung statt passivem Hinweis)
- SSE-Event 'auto_context' ans Frontend senden für Live-Anzeige
- Auto-Context als Message (type=auto_context) in DB speichern
- Aufklappbare Auto-Context-Box im Chat-Stream und History-Rendering

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MelekiandClaude Opus 4.6 committed 2026-04-01 09:28:56 +02:00
1 parent 3f2baa1639
commit 9fe6bed59b
6 files changed
+67 -1

No files matched your search

+10
View File
@@ -64,7 +64,17 @@ public partial class AnthropicService
{
var autoCtx = await BuildAutoContextAsync(messages, chainId, agentId);
if (autoCtx != null)
{
systemPrompt.Add(new { type = "text", text = autoCtx });
await SseHelper.TryWriteSse(response, "auto_context", new { context = autoCtx }, sseCt);
await _db.SaveMessage(new MessageRecord
{
ChainId = chainId,
Role = "system",
Type = "auto_context",
Content = autoCtx
});
}
}
catch (Exception ex)
{
+1 -1
View File
@@ -190,7 +190,7 @@ public partial class AnthropicService
var ctxSb = new StringBuilder();
ctxSb.AppendLine("\n<recalled_context>");
ctxSb.AppendLine("Die folgende Information wurde automatisch abgerufen und könnte relevant sein:");
ctxSb.AppendLine("WICHTIG: Der folgende Kontext wurde automatisch per Vektor-Suche aus früheren Gesprächen und Memory abgerufen. Prüfe diesen Kontext ZUERST, bevor du antwortest. Wenn er zur aktuellen Frage passt, beziehe dich aktiv darauf und nutze die Informationen in deiner Antwort. Ignoriere ihn nur, wenn er eindeutig irrelevant ist.");
foreach (var r in contextResults)
{
var date = DateTime.TryParse(r.CreatedAt, out var dt) ? dt.ToString("yyyy-MM-dd HH:mm") : r.CreatedAt;
+12
View File
@@ -1136,6 +1136,18 @@
padding: var(--box-padding);
}
/* Auto-Context Bubble */
.auto-context-box .tool-box-header .tool-name {
color: var(--info);
}
.auto-context-box .auto-context-content {
padding: var(--box-padding);
font-size: 0.85em;
opacity: 0.85;
}
/* Review Bubbles */
.review-bubble {
+4
View File
@@ -127,6 +127,10 @@ function handleStreamEvent(eventType, data) {
finalizeReviewBubble('done', data, 'finalizer');
break;
case 'auto_context':
addAutoContextBubble(data.context);
break;
case 'info':
addWarningBubble(data.message, true);
break;
+18
View File
@@ -259,6 +259,24 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
}
break;
}
case 'auto_context': {
if (msg.content) {
var acDiv = document.createElement('div');
acDiv.className = 'tool-box auto-context-box' + (archived ? ' archived' : '');
var acHeader = document.createElement('div');
acHeader.className = 'tool-box-header clickable';
acHeader.innerHTML = '<span class="tool-name">Auto-Context</span>';
var acContent = document.createElement('div');
acContent.className = 'auto-context-content';
acContent.textContent = msg.content.replace(/<\/?recalled_context>/g, '').trim();
acContent.hidden = true;
acHeader.addEventListener('click', function() { acContent.hidden = !acContent.hidden; });
acDiv.appendChild(acHeader);
acDiv.appendChild(acContent);
fragment.appendChild(acDiv);
}
break;
}
case 'thinking': {
if (msg.role === 'assistant' && msg.content) {
var thinkDiv = document.createElement('div');
+22
View File
@@ -103,6 +103,28 @@ function endThinkingBubble() {
_thinkingText = '';
}
// ── Auto-Context Bubble ──
function addAutoContextBubble(contextText) {
if (!contextText) return;
var box = document.createElement('div');
box.className = 'tool-box auto-context-box streamed';
var header = document.createElement('div');
header.className = 'tool-box-header clickable';
header.innerHTML = '<span class="tool-name">Auto-Context</span>';
var content = document.createElement('div');
content.className = 'auto-context-content markdown';
content.hidden = true;
// recalled_context aus XML-Tags extrahieren
var inner = contextText.replace(/<\/?recalled_context>/g, '').trim();
content.innerHTML = renderMarkdown(inner);
header.addEventListener('click', function() { content.hidden = !content.hidden; });
box.appendChild(header);
box.appendChild(content);
chatEl().appendChild(box);
scrollDown();
}
// ── Review Bubbles (Streaming) ──
let _reviewBubble = null;