diagnostic/server.js — Handler umgebaut: event: "agent" für Deltas, event: "chat" mit state: "final" für Antworten, extractChatText() parst das content[] Array
bridge/aria_bridge.py — Gleicher Fix: _extract_chat_text() Methode, neue Event-Handler für agent und chat mit state, Legacy-Namen als Fallback
This commit is contained in:
parent
fcb22f60d3
commit
9cad631015
|
|
@ -16,6 +16,15 @@ Alle Änderungen am Projekt. Format: [Keep a Changelog](https://keepachangelog.c
|
|||
- 60s Timeout — markiert Pipeline als fehlgeschlagen wenn keine Antwort kommt
|
||||
- Funktioniert für Gateway-direkt und RVS-Nachrichten
|
||||
|
||||
### Behoben
|
||||
|
||||
**OpenClaw Gateway Event-Format — ARIA antwortet jetzt**
|
||||
- OpenClaw sendet `event: "agent"` (Streaming-Deltas in `payload.data.delta`) und `event: "chat"` mit `payload.state: "delta"|"final"|"error"` — **nicht** `chat:delta`/`chat:final`/`chat:error` wie angenommen
|
||||
- Antworttext steckt in `payload.message.content[0].text` (Array von Content-Blöcken, nicht flacher String) — `text.slice is not a function` Fehler behoben
|
||||
- `ackReactionScope` von `"group-mentions"` auf `"all"` geändert — Agent reagierte nur auf @mentions, nicht auf direkte Nachrichten
|
||||
- Diagnostic Server und Bridge auf neues Event-Format umgestellt
|
||||
- Legacy-Event-Namen (`chat:delta`, `chat:final`, `chat:error`) als Fallback beibehalten
|
||||
|
||||
### Geändert
|
||||
|
||||
**OpenClaw Config — Custom Provider Format**
|
||||
|
|
|
|||
|
|
@ -625,28 +625,30 @@ class ARIABridge:
|
|||
event_name = message.get("event", "")
|
||||
payload = message.get("payload", {})
|
||||
|
||||
if event_name == "chat:delta":
|
||||
# Streaming-Delta — fuer spaeter (Live-Typing in der App)
|
||||
delta = payload.get("delta", payload.get("text", ""))
|
||||
if delta:
|
||||
# ── agent Events: Streaming-Deltas vom LLM ──
|
||||
if event_name == "agent":
|
||||
data = payload.get("data", {})
|
||||
delta = data.get("delta", "")
|
||||
if delta and payload.get("stream") == "assistant":
|
||||
logger.debug("[core] Delta: '%s'", delta[:40])
|
||||
return
|
||||
|
||||
if event_name == "chat:final":
|
||||
# Fertige Antwort von aria-core
|
||||
text = payload.get("text", payload.get("message", ""))
|
||||
if not text:
|
||||
logger.warning("[core] chat:final ohne Text: %s", json.dumps(payload)[:200])
|
||||
return
|
||||
# ── chat Events: Snapshots mit state=delta|final|error ──
|
||||
if event_name == "chat":
|
||||
state = payload.get("state", "")
|
||||
|
||||
if state == "final":
|
||||
text = self._extract_chat_text(payload)
|
||||
if not text:
|
||||
logger.warning("[core] chat final ohne Text: %s", json.dumps(payload)[:200])
|
||||
return
|
||||
logger.info("[core] Antwort: '%s'", text[:80])
|
||||
await self._process_core_response(text, payload)
|
||||
return
|
||||
|
||||
if event_name == "chat:error":
|
||||
error = payload.get("error", payload.get("message", "Unbekannt"))
|
||||
if state == "error":
|
||||
error = payload.get("error", "Unbekannt")
|
||||
logger.error("[core] Chat-Fehler: %s", error)
|
||||
# Fehler auch an die App melden
|
||||
await self._send_to_rvs({
|
||||
"type": "chat",
|
||||
"payload": {
|
||||
|
|
@ -657,9 +659,61 @@ class ARIABridge:
|
|||
})
|
||||
return
|
||||
|
||||
# Andere Events loggen (presence, tick, etc.)
|
||||
# state=delta — periodischer Snapshot, ignorieren
|
||||
return
|
||||
|
||||
# ── Legacy event names (chat:delta, chat:final, chat:error) ──
|
||||
if event_name == "chat:delta":
|
||||
delta = payload.get("delta", payload.get("text", ""))
|
||||
if delta:
|
||||
logger.debug("[core] Delta (legacy): '%s'", delta[:40])
|
||||
return
|
||||
|
||||
if event_name == "chat:final":
|
||||
text = payload.get("text", payload.get("message", ""))
|
||||
if not text:
|
||||
text = self._extract_chat_text(payload)
|
||||
if not text:
|
||||
logger.warning("[core] chat:final ohne Text: %s", json.dumps(payload)[:200])
|
||||
return
|
||||
logger.info("[core] Antwort (legacy): '%s'", text[:80])
|
||||
await self._process_core_response(text, payload)
|
||||
return
|
||||
|
||||
if event_name == "chat:error":
|
||||
error = payload.get("error", payload.get("message", "Unbekannt"))
|
||||
logger.error("[core] Chat-Fehler (legacy): %s", error)
|
||||
await self._send_to_rvs({
|
||||
"type": "chat",
|
||||
"payload": {
|
||||
"text": f"[Fehler] {error}",
|
||||
"sender": "aria",
|
||||
},
|
||||
"timestamp": int(asyncio.get_event_loop().time() * 1000),
|
||||
})
|
||||
return
|
||||
|
||||
# tick, health, etc. — ignorieren
|
||||
if event_name in ("tick", "health"):
|
||||
return
|
||||
|
||||
logger.debug("[core] Event: %s", event_name)
|
||||
|
||||
@staticmethod
|
||||
def _extract_chat_text(payload: dict) -> str:
|
||||
"""Extrahiert Text aus OpenClaw chat-Event message.content Array."""
|
||||
try:
|
||||
content = payload.get("message", {}).get("content", [])
|
||||
if isinstance(content, list):
|
||||
return "".join(
|
||||
c.get("text", "") for c in content if c.get("type") == "text"
|
||||
)
|
||||
if isinstance(content, str):
|
||||
return content
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
return payload.get("text", "")
|
||||
|
||||
async def _process_core_response(self, text: str, payload: dict) -> None:
|
||||
"""Verarbeitet eine fertige Antwort von aria-core.
|
||||
|
||||
|
|
|
|||
|
|
@ -241,6 +241,21 @@ async function connectGateway() {
|
|||
}
|
||||
}
|
||||
|
||||
// Extrahiert Text aus OpenClaw chat-Event message.content Array
|
||||
function extractChatText(payload) {
|
||||
try {
|
||||
const content = payload.message?.content;
|
||||
if (Array.isArray(content)) {
|
||||
return content
|
||||
.filter(c => c.type === "text")
|
||||
.map(c => c.text || "")
|
||||
.join("");
|
||||
}
|
||||
if (typeof payload.message === "string") return payload.message;
|
||||
return payload.text || "";
|
||||
} catch { return ""; }
|
||||
}
|
||||
|
||||
function handleGatewayMessage(msg) {
|
||||
if (msg.type === "res") {
|
||||
const status = msg.ok ? "OK" : `FEHLER: ${JSON.stringify(msg.error).slice(0, 100)}`;
|
||||
|
|
@ -257,24 +272,59 @@ function handleGatewayMessage(msg) {
|
|||
const event = msg.event || "?";
|
||||
const payload = msg.payload || {};
|
||||
|
||||
if (event === "chat:delta") {
|
||||
const delta = payload.delta || payload.text || "";
|
||||
if (delta) {
|
||||
log("info", "gateway", `Delta: "${delta.slice(0, 60)}"`);
|
||||
if (pipelineActive) plog(`Streaming Delta: "${delta.slice(0, 80)}"`);
|
||||
// ── agent Events: Streaming-Deltas vom LLM ──
|
||||
if (event === "agent") {
|
||||
const data = payload.data || {};
|
||||
const delta = data.delta || "";
|
||||
if (delta && payload.stream === "assistant") {
|
||||
broadcast({ type: "chat_delta", delta, payload });
|
||||
}
|
||||
// agent Events nicht einzeln loggen (zu viele)
|
||||
return;
|
||||
}
|
||||
|
||||
if (event === "chat:final") {
|
||||
const text = payload.text || payload.message || "";
|
||||
// ── chat Events: Snapshots mit state=delta|final ──
|
||||
if (event === "chat") {
|
||||
const state = payload.state || "";
|
||||
const text = extractChatText(payload);
|
||||
|
||||
if (state === "final") {
|
||||
log("info", "gateway", `ANTWORT: "${text.slice(0, 200)}"`);
|
||||
if (pipelineActive) pipelineEnd(true, `"${text.slice(0, 120)}"`);
|
||||
broadcast({ type: "chat_final", text, payload });
|
||||
return;
|
||||
}
|
||||
|
||||
if (state === "delta") {
|
||||
// Periodischer Snapshot — nicht einzeln loggen
|
||||
return;
|
||||
}
|
||||
|
||||
if (state === "error") {
|
||||
const error = payload.error || text || "Unbekannt";
|
||||
log("error", "gateway", `Chat-Fehler: ${error}`);
|
||||
if (pipelineActive) pipelineEnd(false, error);
|
||||
broadcast({ type: "chat_error", error, payload });
|
||||
return;
|
||||
}
|
||||
|
||||
log("debug", "gateway", `chat state=${state}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Legacy event names (chat:delta, chat:final, chat:error) ──
|
||||
if (event === "chat:delta") {
|
||||
const delta = payload.delta || payload.text || "";
|
||||
if (delta) broadcast({ type: "chat_delta", delta, payload });
|
||||
return;
|
||||
}
|
||||
if (event === "chat:final") {
|
||||
const text = extractChatText(payload) || payload.text || "";
|
||||
log("info", "gateway", `ANTWORT: "${text.slice(0, 200)}"`);
|
||||
if (pipelineActive) pipelineEnd(true, `"${text.slice(0, 120)}"`);
|
||||
broadcast({ type: "chat_final", text, payload });
|
||||
return;
|
||||
}
|
||||
if (event === "chat:error") {
|
||||
const error = payload.error || payload.message || "Unbekannt";
|
||||
log("error", "gateway", `Chat-Fehler: ${error}`);
|
||||
|
|
@ -283,28 +333,9 @@ function handleGatewayMessage(msg) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Alle anderen Events — vollstaendig loggen fuer Debugging
|
||||
const payloadStr = JSON.stringify(payload).slice(0, 500);
|
||||
log("info", "gateway", `Event: ${event} | ${payloadStr}`);
|
||||
if (pipelineActive) plog(`Gateway Event: ${event} | ${payloadStr.slice(0, 200)}`);
|
||||
|
||||
// "chat" Event koennte die Antwort sein (anderes Format als erwartet)
|
||||
if (event === "chat") {
|
||||
const text = payload.text || payload.message || payload.content || "";
|
||||
const delta = payload.delta || "";
|
||||
const error = payload.error || "";
|
||||
if (error) {
|
||||
log("error", "gateway", `Chat-Fehler (event:chat): ${error}`);
|
||||
if (pipelineActive) pipelineEnd(false, error);
|
||||
broadcast({ type: "chat_error", error, payload });
|
||||
} else if (text) {
|
||||
log("info", "gateway", `ANTWORT (event:chat): "${text.slice(0, 200)}"`);
|
||||
if (pipelineActive) pipelineEnd(true, `"${text.slice(0, 120)}"`);
|
||||
broadcast({ type: "chat_final", text, payload });
|
||||
} else if (delta) {
|
||||
broadcast({ type: "chat_delta", delta, payload });
|
||||
}
|
||||
}
|
||||
// ── Andere Events (tick, health, presence) ──
|
||||
if (event === "tick" || event === "health") return; // Noise
|
||||
log("debug", "gateway", `Event: ${event}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue