diff --git a/diagnostic/index.html b/diagnostic/index.html index cbf9abc..317349f 100644 --- a/diagnostic/index.html +++ b/diagnostic/index.html @@ -57,10 +57,10 @@ .log-entry.warn { color: #FFD60A; } .log-entry.info { color: #AAB; } .log-entry.debug { color: #555570; } - .log-entry.pipeline-step { color: #0096FF; border-left: 2px solid #0096FF; padding-left: 6px; margin: 2px 0; } - .log-entry.pipeline-ok { color: #34C759; border-left: 2px solid #34C759; padding-left: 6px; margin: 2px 0; } - .log-entry.pipeline-err { color: #FF3B30; border-left: 2px solid #FF3B30; padding-left: 6px; margin: 2px 0; } - .log-entry.pipeline-sep { color: #333; margin: 6px 0 2px; } + .log-entry.trace-step { color: #0096FF; border-left: 2px solid #0096FF; padding-left: 6px; margin: 2px 0; } + .log-entry.trace-ok { color: #34C759; border-left: 2px solid #34C759; padding-left: 6px; margin: 2px 0; } + .log-entry.trace-err { color: #FF3B30; border-left: 2px solid #FF3B30; padding-left: 6px; margin: 2px 0; } + .log-entry.trace-sep { color: #333; margin: 6px 0 2px; } .chat-box { background: #080810; border: 1px solid #1E1E2E; border-radius: 6px; min-height: 120px; max-height: 250px; overflow-y: auto; @@ -379,7 +379,7 @@ - +
@@ -398,7 +398,7 @@ - +
@@ -729,8 +729,8 @@ let ws; let activeTab = 'all'; const DOCKER_TABS = ['gateway', 'proxy', 'bridge']; - const autoScroll = { all: true, gateway: true, rvs: true, proxy: true, bridge: true, server: true, pipeline: true }; - const logCounts = { all: 0, gateway: 0, rvs: 0, proxy: 0, bridge: 0, server: 0, pipeline: 0 }; + const autoScroll = { all: true, gateway: true, rvs: true, proxy: true, bridge: true, server: true, trace: true }; + const logCounts = { all: 0, gateway: 0, rvs: 0, proxy: 0, bridge: 0, server: 0, trace: 0 }; const logBoxes = { all: document.getElementById('log-all'), @@ -739,7 +739,7 @@ proxy: document.getElementById('log-proxy'), bridge: document.getElementById('log-bridge'), server: document.getElementById('log-server'), - pipeline: document.getElementById('log-pipeline'), + trace: document.getElementById('log-trace'), tts: document.getElementById('log-tts'), }; @@ -794,7 +794,7 @@ if (source === 'proxy') return 'proxy'; if (source === 'bridge') return 'bridge'; if (source === 'server' || source === 'browser') return 'server'; - if (source === 'pipeline') return 'pipeline'; + if (source === 'trace') return 'trace'; return null; } @@ -1333,12 +1333,12 @@ const time = ts ? new Date(ts).toLocaleTimeString('de-DE') : new Date().toLocaleTimeString('de-DE'); const line = `${time} [${source}] ${message}`; - // Pipeline-Eintraege nur in Pipeline-Tab (nicht in Alle) - if (source === 'pipeline') { - const pipeLevel = level === 'error' ? 'pipeline-err' : level === 'info' && message.includes('>>>') ? 'pipeline-ok' : 'pipeline-step'; - appendToLog('pipeline', pipeLevel, `${time} ${message}`); - logCounts.pipeline++; - document.getElementById('count-pipeline').textContent = logCounts.pipeline; + // Trace-Eintraege nur in Trace-Tab (nicht in Alle) + if (source === 'trace') { + const pipeLevel = level === 'error' ? 'trace-err' : level === 'info' && message.includes('>>>') ? 'trace-ok' : 'trace-step'; + appendToLog('trace', pipeLevel, `${time} ${message}`); + logCounts.trace++; + document.getElementById('count-trace').textContent = logCounts.trace; return; } diff --git a/diagnostic/server.js b/diagnostic/server.js index 6998a1f..067321a 100644 --- a/diagnostic/server.js +++ b/diagnostic/server.js @@ -113,9 +113,9 @@ let rvsWs = null; let reqIdCounter = 0; const browserClients = new Set(); -// ── Pipeline Tracking ────────────────────────────────── -let pipelineActive = false; -let pipelineStartTime = 0; +// ── Trace-Tracking (End-to-End-Mitschnitt einer Anfrage) ────────────────────────────────── +let traceActive = false; +let traceStartTime = 0; // Nach chat:final kommen oft noch Trailing Agent-Events. Waehrend dieses // Fensters unterdruecken wir agent_activity-Broadcasts, damit der @@ -124,40 +124,40 @@ let lastChatFinalAt = 0; const SETTLED_WINDOW_MS = 3000; function plog(message, level) { - const elapsed = pipelineActive ? `+${Date.now() - pipelineStartTime}ms` : ""; - const entry = { ts: new Date().toISOString(), level: level || "info", source: "pipeline", message: `${elapsed ? `[${elapsed}] ` : ""}${message}` }; + const elapsed = traceActive ? `+${Date.now() - traceStartTime}ms` : ""; + const entry = { ts: new Date().toISOString(), level: level || "info", source: "trace", message: `${elapsed ? `[${elapsed}] ` : ""}${message}` }; logs.push(entry); if (logs.length > 500) logs.shift(); - console.log(`[PIPELINE] ${entry.message}`); + console.log(`[TRACE] ${entry.message}`); broadcast({ type: "log", entry }); } -let pipelineTimeout = null; +let traceTimeout = null; -function pipelineStart(method, text) { - // Falls noch eine Pipeline laeuft, beenden - if (pipelineActive) pipelineEnd(false, "Abgebrochen (neue Nachricht)"); - pipelineActive = true; - pipelineStartTime = Date.now(); - if (pipelineTimeout) clearTimeout(pipelineTimeout); - pipelineTimeout = setTimeout(() => { - if (pipelineActive) pipelineEnd(false, "Timeout — keine Antwort nach 10min"); +function traceStart(method, text) { + // Falls noch ein Trace laeuft, beenden + if (traceActive) traceEnd(false, "Abgebrochen (neue Nachricht)"); + traceActive = true; + traceStartTime = Date.now(); + if (traceTimeout) clearTimeout(traceTimeout); + traceTimeout = setTimeout(() => { + if (traceActive) traceEnd(false, "Timeout — keine Antwort nach 10min"); }, 600000); - plog(`━━━ Pipeline Start: ${method} ━━━`); + plog(`━━━ Trace Start: ${method} ━━━`); plog(`Nachricht: "${text}"`); } -function pipelineEnd(ok, detail) { - if (!pipelineActive) return; - if (pipelineTimeout) { clearTimeout(pipelineTimeout); pipelineTimeout = null; } - const elapsed = Date.now() - pipelineStartTime; +function traceEnd(ok, detail) { + if (!traceActive) return; + if (traceTimeout) { clearTimeout(traceTimeout); traceTimeout = null; } + const elapsed = Date.now() - traceStartTime; if (ok) { plog(`>>> Fertig (${elapsed}ms): ${detail}`); } else { plog(`>>> FEHLER (${elapsed}ms): ${detail}`, "error"); } - plog(`━━━ Pipeline Ende ━━━`); - pipelineActive = false; + plog(`━━━ Trace Ende ━━━`); + traceActive = false; // Thinking-Indikator IMMER zuruecksetzen — auch bei Timeout/Fehler/Abbruch broadcast({ type: "agent_activity", activity: "idle" }); pendingMessageTime = 0; @@ -327,8 +327,8 @@ async function connectGateway() { state.gateway.handshakeOk = false; gatewayWs = null; broadcastState(); - // Stuck "ARIA denkt..." vermeiden, falls Gateway waehrend Pipeline abkackt - if (pipelineActive) pipelineEnd(false, `Gateway-Verbindung verloren (${code})`); + // Stuck "ARIA denkt..." vermeiden, falls Gateway waehrend Trace abkackt + if (traceActive) traceEnd(false, `Gateway-Verbindung verloren (${code})`); else broadcast({ type: "agent_activity", activity: "idle" }); checkGatewayHealth(); setTimeout(connectGateway, 5000); @@ -375,7 +375,7 @@ function handleGatewayMessage(msg) { if (msg.type === "res") { const status = msg.ok ? "OK" : `FEHLER: ${JSON.stringify(msg.error).slice(0, 100)}`; log("info", "gateway", `Response [${msg.id}]: ${status}`); - if (pipelineActive) { + if (traceActive) { if (msg.ok) plog(`Gateway ACK [${msg.id}] — Nachricht angenommen`); else plog(`Gateway NACK [${msg.id}] — ${JSON.stringify(msg.error).slice(0, 100)}`, "error"); } @@ -427,12 +427,12 @@ function handleGatewayMessage(msg) { if (runId && seenFinalRuns.has(runId)) return; // Duplikat if (runId) { seenFinalRuns.add(runId); setTimeout(() => seenFinalRuns.delete(runId), 60000); } - // NO_REPLY → ARIA signalisiert "nicht antworten", Pipeline beenden aber nichts zeigen + // NO_REPLY → ARIA signalisiert "nicht antworten", Trace beenden aber nichts zeigen const trimmed = (text || "").trim().replace(/^["'`*.\s]+|["'`*.\s]+$/g, "").toUpperCase(); if (trimmed === "NO_REPLY" || trimmed.startsWith("NO_REPLY")) { log("info", "gateway", "NO_REPLY empfangen — still verworfen"); lastChatFinalAt = Date.now(); - if (pipelineActive) pipelineEnd(true, "NO_REPLY (stumm)"); + if (traceActive) traceEnd(true, "NO_REPLY (stumm)"); broadcast({ type: "agent_activity", activity: "idle" }); pendingMessageTime = 0; updateAgentActivity(); @@ -441,7 +441,7 @@ function handleGatewayMessage(msg) { log("info", "gateway", `ANTWORT: "${text.slice(0, 200)}"`); lastChatFinalAt = Date.now(); - if (pipelineActive) pipelineEnd(true, `"${text.slice(0, 120)}"`); + if (traceActive) traceEnd(true, `"${text.slice(0, 120)}"`); broadcast({ type: "chat_final", text, payload }); broadcast({ type: "agent_activity", activity: "idle" }); pendingMessageTime = 0; // Watchdog: Antwort erhalten @@ -462,7 +462,7 @@ function handleGatewayMessage(msg) { if (state === "error") { const error = payload.error || text || "Unbekannt"; log("error", "gateway", `Chat-Fehler: ${error}`); - if (pipelineActive) pipelineEnd(false, error); + if (traceActive) traceEnd(false, error); else broadcast({ type: "agent_activity", activity: "idle" }); broadcast({ type: "chat_error", error, payload }); return; @@ -485,7 +485,7 @@ function handleGatewayMessage(msg) { const text = extractChatText(payload) || payload.text || ""; log("info", "gateway", `ANTWORT: "${text.slice(0, 200)}"`); lastChatFinalAt = Date.now(); - if (pipelineActive) pipelineEnd(true, `"${text.slice(0, 120)}"`); + if (traceActive) traceEnd(true, `"${text.slice(0, 120)}"`); else broadcast({ type: "agent_activity", activity: "idle" }); broadcast({ type: "chat_final", text, payload }); return; @@ -493,7 +493,7 @@ function handleGatewayMessage(msg) { if (event === "chat:error") { const error = payload.error || payload.message || "Unbekannt"; log("error", "gateway", `Chat-Fehler: ${error}`); - if (pipelineActive) pipelineEnd(false, error); + if (traceActive) traceEnd(false, error); else broadcast({ type: "agent_activity", activity: "idle" }); broadcast({ type: "chat_error", error, payload }); return; @@ -505,10 +505,10 @@ function handleGatewayMessage(msg) { } } -function sendToGateway(text, isPipeline) { +function sendToGateway(text, isTrace) { if (!gatewayWs || gatewayWs.readyState !== WebSocket.OPEN) { log("error", "gateway", "Nicht verbunden — kann nicht senden"); - if (isPipeline) pipelineEnd(false, "Gateway nicht verbunden"); + if (isTrace) traceEnd(false, "Gateway nicht verbunden"); return false; } @@ -535,7 +535,7 @@ function sendToGateway(text, isPipeline) { fs.appendFileSync("/shared/config/chat_backup.jsonl", entry); } catch {} log("info", "gateway", `chat.send [${reqId}]: "${text}"`); - if (isPipeline) plog(`chat.send [${reqId}] an Gateway gesendet — warte auf ACK...`); + if (isTrace) plog(`chat.send [${reqId}] an Gateway gesendet — warte auf ACK...`); // Gateway-Nachrichten NICHT an RVS senden (sonst doppelter ARIA-Request via Bridge) return true; @@ -605,8 +605,8 @@ function connectRVS(forcePlain) { // Eigene Nachrichten ignorieren (Echo) if (sender === "diagnostic") return; log("info", "rvs", `Chat von ${sender}: "${(msg.payload.text || "").slice(0, 100)}"`); - if (pipelineActive) { - pipelineEnd(true, `Antwort via RVS von ${sender}: "${(msg.payload.text || "").slice(0, 120)}"`); + if (traceActive) { + traceEnd(true, `Antwort via RVS von ${sender}: "${(msg.payload.text || "").slice(0, 120)}"`); } broadcast({ type: "rvs_chat", msg }); } else if (msg.type === "file_saved" && msg.payload) { @@ -744,14 +744,14 @@ function sendToRVS_raw(msgObj) { freshWs.on("error", () => {}); } -function sendToRVS(text, isPipeline) { +function sendToRVS(text, isTrace) { // Ueber Gateway senden (zuverlaessig) UND an RVS fuer App-Sichtbarkeit // Die Bridge empfaengt RVS-Nachrichten von der App zuverlaessig, // aber die Diagnostic→RVS→Bridge Route hat Zombie-Probleme. // Deshalb: Gateway fuer ARIA, RVS nur fuer App-Anzeige. // 1. An Gateway senden (damit ARIA antwortet) - const gatewayOk = sendToGateway(text, isPipeline); + const gatewayOk = sendToGateway(text, isTrace); // 2. An RVS senden (damit die App die Nachricht sieht) sendToRVS_raw({ @@ -1337,7 +1337,7 @@ const server = http.createServer((req, res) => { pendingMessageTime = 0; watchdogWarned = false; watchdogFixAttempted = false; - if (pipelineActive) pipelineEnd(false, "Vom Benutzer abgebrochen (App)"); + if (traceActive) traceEnd(false, "Vom Benutzer abgebrochen (App)"); else broadcast({ type: "agent_activity", activity: "idle" }); dockerExec("aria-core", "openclaw doctor --fix 2>/dev/null || true").catch(() => {}); res.writeHead(200, { "Content-Type": "application/json" }); @@ -1475,10 +1475,10 @@ wss.on("connection", (ws) => { const msg = JSON.parse(raw.toString()); if (msg.action === "test_gateway") { - pipelineStart("Gateway", msg.text || "aria lebst du noch?"); + traceStart("Gateway", msg.text || "aria lebst du noch?"); sendToGateway(msg.text || "aria lebst du noch?", true); } else if (msg.action === "test_rvs") { - pipelineStart("RVS", msg.text || "aria lebst du noch?"); + traceStart("RVS", msg.text || "aria lebst du noch?"); sendToRVS(msg.text || "aria lebst du noch?", true); } else if (msg.action === "reconnect_gateway") { connectGateway(); @@ -1521,7 +1521,7 @@ wss.on("connection", (ws) => { pendingMessageTime = 0; watchdogWarned = false; watchdogFixAttempted = false; - if (pipelineActive) pipelineEnd(false, "Vom Benutzer abgebrochen"); + if (traceActive) traceEnd(false, "Vom Benutzer abgebrochen"); broadcast({ type: "agent_activity", activity: "idle" }); dockerExec("aria-core", "openclaw doctor --fix 2>/dev/null || true").catch(() => {}); } else if (msg.action === "voice_upload") {