feat: Auto-Compact nach N User-Messages — verhindert E2BIG bei langer Session
E2BIG (Argument list too long) tritt auf wenn aria-core's Subprocess-
Spawn das Linux argv-Limit (~128KB-2MB) sprengt. Bei >140 Messages
samt Memory + System-Prompt + Tools laeuft das voll, ARIA antwortet
nur noch leer auf jede Anfrage.
Bridge zaehlt jetzt User-Nachrichten in send_to_core; bei COMPACT_AFTER_MESSAGES
(env, default 140) wird automatisch:
- Sessions geleert (rm sessions/*.jsonl + sessions.json = {})
- aria-core neu gestartet
- User informiert "Konversation komprimiert, letzte Nachricht nochmal"
Plus manueller "🧹 Konversation komprimieren"-Button in App-Settings
und 🧹 Compact-Button in Diagnostic-Thinking-Indicator.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -549,6 +549,12 @@ class ARIABridge:
|
||||
# Beeinflusst das Timeout fuer stt_request — bei "loading" warten wir laenger,
|
||||
# weil das Modell beim ersten Request noch ~1-2 Min runtergeladen werden kann.
|
||||
self._remote_stt_ready: bool = False
|
||||
# User-Message-Counter fuer Auto-Compact. Bei zu langer Konversation
|
||||
# sprengt die argv-Liste beim Claude-Subprocess-Spawn (E2BIG). Bei
|
||||
# COMPACT_AFTER erreicht → Sessions reset + Container restart.
|
||||
# Counter ueberlebt Bridge-Restart nicht (frischer Zaehler beim Start ok).
|
||||
self._user_message_count: int = 0
|
||||
self._compact_after = int(os.getenv("COMPACT_AFTER_MESSAGES", "140"))
|
||||
# Pending Files: wenn die App ein Bild + Text gleichzeitig schickt, kommen
|
||||
# zwei separate RVS-Events ('file' und 'chat') — wir buffern die Files
|
||||
# kurz und mergen sie mit dem nachfolgenden Chat-Text zu einer einzigen
|
||||
@@ -1170,12 +1176,53 @@ class ARIABridge:
|
||||
await self.send_to_core(text, source="app-file+chat")
|
||||
return True
|
||||
|
||||
async def _trigger_session_reset(self) -> None:
|
||||
"""Sessions loeschen + Container restart via Diagnostic HTTP-API."""
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
"http://localhost:3001/api/aria-session-reset",
|
||||
data=b"{}",
|
||||
method="POST",
|
||||
headers={"Content-Type": "application/json"},
|
||||
)
|
||||
def _do_reset():
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=45) as resp:
|
||||
return resp.status
|
||||
except Exception as e:
|
||||
return f"err:{e}"
|
||||
result = await asyncio.get_event_loop().run_in_executor(None, _do_reset)
|
||||
logger.info("[core] Session-Reset Result: %s", result)
|
||||
except Exception as e:
|
||||
logger.warning("[core] Session-Reset Trigger fehlgeschlagen: %s", e)
|
||||
|
||||
async def send_to_core(self, text: str, source: str = "bridge") -> None:
|
||||
"""Sendet Text an aria-core (OpenClaw chat.send Protokoll)."""
|
||||
if self.ws_core is None:
|
||||
logger.error("[core] Nicht verbunden — Nachricht verworfen: '%s'", text[:60])
|
||||
return
|
||||
|
||||
# Auto-Compact: bei zu vielen User-Messages laeuft argv beim Subprocess-
|
||||
# Spawn ueber (E2BIG). Vor send pruefen, ggf. Sessions resetten.
|
||||
if source.startswith("app") and self._compact_after > 0:
|
||||
self._user_message_count += 1
|
||||
if self._user_message_count >= self._compact_after:
|
||||
logger.warning("[core] Auto-Compact: %d Messages erreicht — Session-Reset",
|
||||
self._user_message_count)
|
||||
self._user_message_count = 0
|
||||
# Reset triggern via Diagnostic (asynchron, blockiert send nicht)
|
||||
asyncio.create_task(self._trigger_session_reset())
|
||||
# User informieren — der naechste Request kommt erst nach Restart durch
|
||||
await self._send_to_rvs({
|
||||
"type": "chat",
|
||||
"payload": {
|
||||
"text": f"[Compact] Konversation war lang ({self._compact_after} Nachrichten) — Session wurde geleert, ARIA startet frisch. Deine letzte Nachricht bitte gleich nochmal senden.",
|
||||
"sender": "aria",
|
||||
},
|
||||
"timestamp": int(asyncio.get_event_loop().time() * 1000),
|
||||
})
|
||||
return
|
||||
|
||||
# Aktive Session vom Diagnostic holen
|
||||
self._fetch_active_session()
|
||||
|
||||
@@ -1580,6 +1627,13 @@ class ARIABridge:
|
||||
except Exception as e:
|
||||
logger.warning("[rvs] file_saved konnte nicht an App gesendet werden: %s", e)
|
||||
|
||||
elif msg_type == "aria_session_reset":
|
||||
# Manueller Compact-Trigger: Sessions weg + Restart
|
||||
logger.warning("[rvs] aria_session_reset Request von App")
|
||||
self._user_message_count = 0
|
||||
asyncio.create_task(self._trigger_session_reset())
|
||||
return
|
||||
|
||||
elif msg_type == "aria_restart":
|
||||
# App-Button "ARIA hart neu starten" → docker restart aria-core
|
||||
# via Diagnostic (der hat den Docker-Socket gemountet).
|
||||
|
||||
Reference in New Issue
Block a user