Bug: Wenn der Brain-Background-Loop einen Timer/Watcher feuert, ruft
er agent.chat() direkt im eigenen Prozess. Die Antwort wurde nur ins
Trigger-Log geschrieben — kein RVS-Broadcast, kein TTS, nichts in
App/Diagnostic sichtbar.
Fix: Bridge ↔ Brain bekommen einen internen HTTP-Push-Kanal.
Bridge (Port 8090, nicht exposed, nur aria-net intern):
asyncio.start_server-basierter HTTP-Listener.
POST /internal/trigger-fired
body: {reply, trigger_name, type, events}
→ _handle_trigger_fired feuert Side-Channel-Events
(trigger_created/skill_created/location_tracking) erst,
dann _process_core_response(reply) — exakt der gleiche Pfad
wie normale Chat-Antworten (Chat-Bubble + TTS + chat_backup).
Brain background.py:
Nach agent.chat() in _fire wird agent.pop_events() ausgelesen
und zusammen mit dem Reply via urllib an aria-bridge:8090
gepostet (run_in_executor damit es den asyncio-Loop nicht
blockiert). Failures werden geloggt, der Trigger selbst bleibt
trotzdem als 'fired' markiert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ARIA hatte bisher nur ein "User fragt → Brain antwortet"-Modell. Neu:
Trigger laufen passiv im Hintergrund (kein LLM-Call) und wecken ARIA
nur dann auf wenn ein Event tatsaechlich passiert.
Drei Typen, zwei aktuell implementiert:
timer — einmalig zu festem ISO-Timestamp ("erinner mich in 10min")
watcher — Polling alle N Sek einer Condition, feuert bei True mit Throttle
(z.B. "disk_free_gb < 5", max 1x/h)
cron — Platzhalter fuer spaeter
aria-brain/triggers.py
CRUD auf /data/triggers/<name>.json + /data/triggers/logs/<name>.jsonl.
create_timer, create_watcher, mark_fired, list_logs, etc.
aria-brain/watcher.py
Built-in Condition-Variablen: disk_free_gb, disk_free_pct, uptime_sec,
hour_of_day, day_of_week, rvs_connected, memory_count.
Sicherer Condition-Parser via ast — Whitelist auf Vergleich + BoolOp +
Name + Const. Kein eval, kein exec, keine Builtins.
aria-brain/background.py
Async Loop laeuft alle 30s, sammelt einmalig Variables, geht durch
Trigger-Liste, _should_fire-Check (Timer: fires_at vergangen / Watcher:
check_interval + throttle respektiert + condition true). Fire ruft
agent.chat(prompt, source="trigger") — ARIA bekommt das wie eine
Push-Nachricht und antwortet via Bridge → RVS → App.
aria-brain/main.py
/triggers/list, /{name}, /{name}/logs, /timer, /watcher, PATCH, DELETE,
/triggers/conditions (Variablen + aktuelle Werte). Lifespan-Handler
startet den Background-Loop beim Container-Start, stoppt beim Shutdown.
aria-brain/agent.py
Meta-Tools fuer ARIA: trigger_timer, trigger_watcher, trigger_cancel,
trigger_list. ARIA legt Trigger via Tool-Call selbst an wenn Stefan das
wuenscht. Side-Channel-Event 'trigger_created' wird in chat-Response
mitgeschickt damit App + Diagnostic eine Bubble zeigen.
aria-brain/prompts.py
Neue System-Prompt-Section: Liste aktiver Triggers + verfuegbare
Condition-Variablen mit aktuellen Werten + Operatoren-Erklaerung.
ARIA weiss damit immer was es schon gibt und welche Vars sie nutzen kann.
bridge/aria_bridge.py + rvs/server.js
trigger_created als neuer RVS-Message-Type, Bridge forwarded das aus
data.events analog zu skill_created.
diagnostic/index.html
Neuer Top-Tab "Trigger". Liste mit Type-Badges (⏱ TIMER / 👁 WATCHER),
Status, Fire-Count, last_fired. Aktivieren/Deaktivieren + Löschen pro
Trigger. "+ Neu"-Modal mit Type-Dropdown, Timer-Minuten oder
Watcher-Condition + Vars-Anzeige + Throttle. Info-Modal-Eintrag mit
Erklaerung. Live-Bubble im Chat wenn ARIA selbst einen anlegt.
android/src/screens/ChatScreen.tsx
trigger_created RVS-Handler → eigene Bubble (gelber Border, "⏰ ARIA
hat einen Trigger angelegt", Type/Detail/Message/Zeit). ChatMessage
bekam triggerCreated-Feld. Lokal-only-Schutz beim Server-Sync analog
zu skill_created.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>