@@ -361,7 +367,10 @@
const proto = location.protocol === 'https:' ? 'wss' : 'ws';
ws = new WebSocket(`${proto}://${location.host}`);
- ws.onopen = () => addLog('info', 'browser', 'Verbunden mit Diagnostic Server');
+ ws.onopen = () => {
+ addLog('info', 'browser', 'Verbunden mit Diagnostic Server');
+ send({ action: 'get_active_session' });
+ };
ws.onclose = () => {
addLog('warn', 'browser', 'Verbindung zum Diagnostic Server verloren — Reconnect in 2s');
setTimeout(connectWS, 2000);
@@ -461,10 +470,23 @@
if (msg.type === 'sessions_list') { renderSessions(msg); return; }
if (msg.type === 'session_detail') { renderSessionDetail(msg); return; }
if (msg.type === 'session_deleted') {
- if (msg.ok) loadSessions(); // Liste neu laden
+ if (msg.ok) loadSessions();
else alert('Loeschen fehlgeschlagen: ' + (msg.error || '?'));
return;
}
+ if (msg.type === 'active_session') {
+ updateActiveSessionBar(msg.sessionKey);
+ loadSessions(); // Tabelle neu rendern
+ return;
+ }
+ if (msg.type === 'session_created') {
+ if (msg.ok) {
+ loadSessions();
+ } else {
+ alert('Session erstellen fehlgeschlagen: ' + (msg.error || '?'));
+ }
+ return;
+ }
if (msg.type === 'brain_list') { renderBrainList(msg); return; }
if (msg.type === 'brain_content') { renderBrainContent(msg); return; }
if (msg.type === 'response') { return; }
@@ -848,6 +870,8 @@
send({ action: 'list_sessions' });
}
+ let currentActiveSession = '';
+
function renderSessions(data) {
const container = document.getElementById('sessions-list');
if (data.error) {
@@ -871,14 +895,19 @@
const key = escapeHtml(s.sessionKey || s.path.split('/').pop());
const orphanBadge = s.orphan ? '
verwaist' : '';
const modelBadge = s.model ? `
${escapeHtml(s.model)}
` : '';
- const keyColor = s.orphan ? '#555570' : '#E0E0F0';
- html += `
`
+ const isActive = (s.sessionKey === currentActiveSession);
+ const keyColor = isActive ? '#34C759' : (s.orphan ? '#555570' : '#E0E0F0');
+ const activeBadge = isActive ? ' aktiv' : '';
+ const rowBg = isActive ? 'background:rgba(52,199,89,0.08);' : '';
+ html += `
`
+ `| `
- + ` ${key}${orphanBadge} ${modelBadge} | `
+ + `${key}${activeBadge}${orphanBadge}
${modelBadge}`
+ `${s.lines} | `
+ `${date} | `
- + ` | `
- + '
';
+ + `
`
+ + (isActive ? '' : ``)
+ + ``
+ + ` | `;
}
html += '';
container.innerHTML = html;
@@ -941,6 +970,28 @@
send({ action: 'delete_session', sessionPath: path });
}
+ function activateSession(sessionKey) {
+ send({ action: 'set_active_session', sessionKey });
+ }
+
+ function createSession() {
+ const name = prompt('Name fuer neue Session (a-z, 0-9, -, _):');
+ if (!name) return;
+ send({ action: 'create_session', sessionName: name.trim() });
+ }
+
+ function updateActiveSessionBar(sessionKey) {
+ currentActiveSession = sessionKey || '';
+ const bar = document.getElementById('active-session-bar');
+ const nameEl = document.getElementById('active-session-name');
+ if (currentActiveSession) {
+ bar.style.display = 'block';
+ nameEl.textContent = currentActiveSession;
+ } else {
+ bar.style.display = 'none';
+ }
+ }
+
// ── Brain Viewer ────────────────────────────────────────
function loadBrain() {
diff --git a/diagnostic/server.js b/diagnostic/server.js
index 1eadca4..2d55ba7 100644
--- a/diagnostic/server.js
+++ b/diagnostic/server.js
@@ -35,6 +35,7 @@ const state = {
rvs: { status: "disconnected", lastError: null },
proxy: { status: "unknown", lastError: null },
};
+let activeSessionKey = "aria-diag-v3";
const logs = [];
let gatewayWs = null;
let rvsWs = null;
@@ -385,7 +386,7 @@ function sendToGateway(text, isPipeline) {
id: reqId,
method: "chat.send",
params: {
- sessionKey: "aria-diag-v3",
+ sessionKey: activeSessionKey,
message: text,
idempotencyKey: crypto.randomUUID(),
},
@@ -976,6 +977,12 @@ wss.on("connection", (ws) => {
handleReadSession(ws, msg.sessionPath);
} else if (msg.action === "delete_session") {
handleDeleteSession(ws, msg.sessionPath);
+ } else if (msg.action === "set_active_session") {
+ handleSetActiveSession(ws, msg.sessionKey);
+ } else if (msg.action === "get_active_session") {
+ ws.send(JSON.stringify({ type: "active_session", sessionKey: activeSessionKey }));
+ } else if (msg.action === "create_session") {
+ handleCreateSession(ws, msg.sessionName);
} else if (msg.action === "list_brain") {
handleListBrain(ws);
} else if (msg.action === "read_brain_file") {
@@ -1230,7 +1237,31 @@ async function handleDeleteSession(clientWs, sessionPath) {
}
try {
log("warn", "server", `Loesche Session: ${sessionPath}`);
- await dockerExec("aria-core", `rm '${sessionPath.replace(/'/g, "")}'`);
+ const safePath = sessionPath.replace(/'/g, "");
+ // Session-ID aus Pfad extrahieren (UUID.jsonl)
+ const filename = safePath.split("/").pop();
+ const sessionId = filename.replace(".jsonl", "");
+
+ // 1. JSONL-Datei loeschen
+ await dockerExec("aria-core", `rm -f '${safePath}'`);
+
+ // 2. Eintrag aus sessions.json entfernen
+ try {
+ const sFile = `${SESSIONS_DIR}/sessions.json`;
+ const script = [
+ 'const fs=require("fs");',
+ `const f="${sFile}",sid="${sessionId}";`,
+ 'try{const d=JSON.parse(fs.readFileSync(f,"utf8"));',
+ 'for(const k of Object.keys(d)){const v=d[k];',
+ 'if(v&&(v.sessionId===sid||v.id===sid))delete d[k];}',
+ 'fs.writeFileSync(f,JSON.stringify(d,null,2));}catch(e){}',
+ ].join("");
+ const b64 = Buffer.from(script).toString("base64");
+ await dockerExec("aria-core", `echo ${b64} | base64 -d | node`);
+ } catch (e) {
+ log("warn", "server", `sessions.json Update fehlgeschlagen: ${e.message}`);
+ }
+
clientWs.send(JSON.stringify({ type: "session_deleted", ok: true, path: sessionPath }));
log("info", "server", "Session geloescht");
} catch (err) {
@@ -1238,6 +1269,40 @@ async function handleDeleteSession(clientWs, sessionPath) {
}
}
+// ── Session aktivieren ─────────────────────────────────
+function handleSetActiveSession(clientWs, sessionKey) {
+ if (!sessionKey || typeof sessionKey !== "string") {
+ clientWs.send(JSON.stringify({ type: "active_session", ok: false, error: "Kein sessionKey" }));
+ return;
+ }
+ activeSessionKey = sessionKey;
+ log("info", "server", `Aktive Session: ${activeSessionKey}`);
+ // Allen Clients mitteilen
+ for (const c of browserClients) {
+ c.send(JSON.stringify({ type: "active_session", sessionKey: activeSessionKey }));
+ }
+}
+
+// ── Session erstellen ──────────────────────────────────
+async function handleCreateSession(clientWs, sessionName) {
+ if (!sessionName || typeof sessionName !== "string" || !/^[a-zA-Z0-9_-]+$/.test(sessionName)) {
+ clientWs.send(JSON.stringify({ type: "session_created", ok: false, error: "Ungueltiger Name (nur a-z, 0-9, -, _)" }));
+ return;
+ }
+ try {
+ // Session wird automatisch erstellt wenn man die erste Nachricht sendet
+ activeSessionKey = sessionName;
+ log("info", "server", `Neue Session erstellt und aktiviert: ${sessionName}`);
+ // Allen Clients mitteilen
+ for (const c of browserClients) {
+ c.send(JSON.stringify({ type: "active_session", sessionKey: activeSessionKey }));
+ }
+ clientWs.send(JSON.stringify({ type: "session_created", ok: true, sessionKey: sessionName }));
+ } catch (err) {
+ clientWs.send(JSON.stringify({ type: "session_created", ok: false, error: err.message }));
+ }
+}
+
// ── Brain Viewer ────────────────────────────────────────
async function handleListBrain(clientWs) {