fix(diagnostic): ARIA-Datei-Bubbles ueberleben Browser-Refresh

Beim Page-Reload laedt Diagnostic die Chat-History aus dem OpenClaw-
Session-File. file_from_aria-Events sind nur live-broadcast, nicht im
jsonl gespeichert → nach F5 waren die Anhang-Bubbles weg.

Fix: Server parsed [FILE: ...]-Marker aus assistant-messages beim
History-Load und schickt fuer existierende Files ein "aria_file"-
Message-Stueck mit allen Metadaten (Pfad, MIME, Groesse). Frontend
ruft addAriaFile mit denen, sodass die Bubbles wieder erscheinen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 19:08:06 +02:00
parent 2100c64b91
commit d7e7386954
2 changed files with 38 additions and 2 deletions
+9 -1
View File
@@ -1098,9 +1098,17 @@
chatBox.innerHTML = '';
if (msg.messages && msg.messages.length > 0) {
for (const m of msg.messages) {
if (m.type === 'aria_file') {
// ARIA-Datei-Bubble rekonstruieren (statt addAriaFile damit
// kein Auto-Scroll-Race waehrend des Bulk-Loads)
addAriaFile({ serverPath: m.serverPath, name: m.name, mimeType: m.mimeType, size: m.size });
continue;
}
const el = document.createElement('div');
el.className = `chat-msg ${m.type}`;
const escaped = escapeHtml(m.text);
// [FILE: ...]-Marker rausfiltern (gleicher Filter wie addChat)
const cleaned = (m.text || '').replace(/\[FILE:\s*\/shared\/uploads\/[^\]]+\]/gi, '').replace(/\n{3,}/g, '\n\n').trim();
const escaped = escapeHtml(cleaned);
const linked = linkifyText(escaped);
const time = m.ts ? new Date(m.ts).toLocaleTimeString('de-DE') : '?';
el.innerHTML = `${linked}<div class="meta">${escapeHtml(m.meta)}${time}</div>`;
+29 -1
View File
@@ -2231,7 +2231,35 @@ async function handleLoadChatHistory(clientWs) {
} else if (role === "assistant") {
// Reply-Prefix entfernen: "[[reply_to_current]] "
text = text.replace(/^\[\[reply_to_\w+\]\]\s*/g, "").trim();
if (text) chatMessages.push({ type: "received", text, meta: "chat:final", ts: msg.timestamp || obj.timestamp || 0 });
const ts = msg.timestamp || obj.timestamp || 0;
// ARIA-File-Marker aus dem Text parsen — pro existierender Datei
// eine separate file_from_aria-aehnliche Message einfuegen damit die
// Anhang-Bubble nach Browser-Refresh wieder erscheint.
const fileRe = /\[FILE:\s*(\/shared\/uploads\/[^\]]+?)\s*\]/gi;
let m;
while ((m = fileRe.exec(text)) !== null) {
const p = m[1].trim();
try {
if (fs.existsSync(p)) {
const st = fs.statSync(p);
const ext = path.extname(p).toLowerCase();
const mimeMap = { ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".gif": "image/gif",
".webp": "image/webp", ".svg": "image/svg+xml", ".pdf": "application/pdf",
".mp3": "audio/mpeg", ".mid": "audio/midi", ".midi": "audio/midi",
".wav": "audio/wav", ".txt": "text/plain", ".md": "text/markdown",
".json": "application/json", ".zip": "application/zip" };
chatMessages.push({
type: "aria_file",
serverPath: p,
name: path.basename(p),
mimeType: mimeMap[ext] || "application/octet-stream",
size: st.size,
ts,
});
}
} catch {}
}
if (text) chatMessages.push({ type: "received", text, meta: "chat:final", ts });
}
} catch {}
}