feat(brain): GPS-Variablen + near()-Helper + erweiterte Condition-Vars
ARIA kann jetzt GPS-basierte Watcher-Trigger anlegen (Blitzer-Warner-Use-Case),
plus erweiterte Time-, System- und Activity-Variablen.
bridge/aria_bridge.py
_persist_state() schreibt atomar nach /shared/state/<key>.json.
Bei jedem chat- und audio-Event:
- location → /shared/state/location.json {lat, lon, ts_unix}
- last_user_ts → /shared/state/activity.json
Brain-Watcher lesen das fuer die GPS- und Activity-Variablen.
aria-brain/watcher.py — komplett ueberarbeitet
Neue Variablen-Sets:
GPS: current_lat, current_lon, location_age_sec (-1 = nie gesehen)
Zeit (+): minute_of_hour, day_of_month, month, year, is_weekend, unix_timestamp
System: ram_free_mb (MemAvailable), cpu_load_1min (loadavg)
Activity: last_user_message_ago_sec
Memory: pinned_count (zusaetzlich zu memory_count)
Neue Funktion fuer Conditions:
near(lat, lon, radius_m) Haversine-Distanz von current_lat/lon
zum Punkt. False wenn keine Position bekannt.
Parser-Erweiterung:
ast.Call jetzt erlaubt, ABER nur fuer direkte Funktionsnamen aus der
Whitelist (_ALLOWED_FUNCTIONS = {"near"}). Keine Attribute-Access,
keine Keywords, Args nur Constants/Names/UnaryOp.
Selbsttest blockt korrekt:
__import__("os")... → "Funktionsaufruf nur ueber direkten Namen"
memory_count.__class__ → "Verbotener Ausdruck: Attribute"
(lambda: 1)() → "Funktionsaufruf nur ueber direkten Namen"
aria-brain/main.py
/triggers/conditions liefert jetzt zusaetzlich {functions:[...]} mit
Signaturen + Beschreibungen. current-Snapshot filtert callable() raus
damit JSON serialisierbar bleibt.
aria-brain/prompts.py + agent.py
build_triggers_section bekommt condition_funcs als 4tes Argument und
listet die im System-Prompt unter "Verfuegbare Funktionen". Operatoren-
Hinweis ergaenzt mit Beispielen + Regeln (keine Variablen in Funktions-
Args, keine Schachtelung).
diagnostic/index.html
Trigger-Create-Modal: Variablen-Info-Block zeigt jetzt sowohl Variablen
(mit aktuellen Werten) als auch Funktionen (Signatur + Beschreibung).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+18
-6
@@ -115,8 +115,12 @@ def build_skills_section(skills: List[dict]) -> str:
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def build_triggers_section(triggers: List[dict], condition_vars: List[dict]) -> str:
|
||||
"""Triggers (passive Aufweck-Quellen) + verfuegbare Condition-Variablen."""
|
||||
def build_triggers_section(
|
||||
triggers: List[dict],
|
||||
condition_vars: List[dict],
|
||||
condition_funcs: List[dict] | None = None,
|
||||
) -> str:
|
||||
"""Triggers (passive Aufweck-Quellen) + verfuegbare Condition-Variablen + Funktionen."""
|
||||
lines = ["## Trigger (passive Aufweck-Quellen)"]
|
||||
lines.append("")
|
||||
lines.append("Trigger sind ANDERS als Skills: das System ruft DICH wenn ein Event passiert. "
|
||||
@@ -135,14 +139,21 @@ def build_triggers_section(triggers: List[dict], condition_vars: List[dict]) ->
|
||||
lines.append("### Verfuegbare Condition-Variablen (fuer Watcher)")
|
||||
for v in condition_vars:
|
||||
lines.append(f"- `{v['name']}` ({v['type']}) — {v['desc']}")
|
||||
if condition_funcs:
|
||||
lines.append("")
|
||||
lines.append("### Verfuegbare Funktionen in Conditions")
|
||||
for fn in condition_funcs:
|
||||
lines.append(f"- `{fn['signature']}` — {fn['desc']}")
|
||||
lines.append("")
|
||||
lines.append("Operatoren in Conditions: `<` `>` `<=` `>=` `==` `!=` `and` `or` `not`. "
|
||||
"Beispiel: `disk_free_gb < 5 and hour_of_day >= 8`. "
|
||||
"String-Werte in Quotes: `day_of_week == \"mon\"`.")
|
||||
"Beispiele: `disk_free_gb < 5 and hour_of_day >= 8`, "
|
||||
"`day_of_week == \"mon\"`, `near(53.123, 7.456, 500)`. "
|
||||
"Funktionen nur mit Konstanten als Argumenten (keine Variablen, "
|
||||
"keine geschachtelten Funktionen).")
|
||||
lines.append("")
|
||||
lines.append("### Wann welcher Typ?")
|
||||
lines.append("- **Timer** fuer einmalige Erinnerungen mit konkreter Zeit ('in 10min', 'um 14:30').")
|
||||
lines.append("- **Watcher** fuer 'wenn X passiert' (Disk voll, bestimmte Tageszeit).")
|
||||
lines.append("- **Watcher** fuer 'wenn X passiert' (Disk voll, bestimmte Tageszeit, GPS-Naehe).")
|
||||
lines.append("- ARIA legt Trigger NUR auf Stefan-Wunsch an, nicht eigenmaechtig.")
|
||||
return "\n".join(lines)
|
||||
|
||||
@@ -153,6 +164,7 @@ def build_system_prompt(
|
||||
skills: List[dict] | None = None,
|
||||
triggers: List[dict] | None = None,
|
||||
condition_vars: List[dict] | None = None,
|
||||
condition_funcs: List[dict] | None = None,
|
||||
) -> str:
|
||||
"""Kompletter System-Prompt: Hot + Cold + Skills + Triggers."""
|
||||
parts = [build_hot_memory_section(pinned)]
|
||||
@@ -161,7 +173,7 @@ def build_system_prompt(
|
||||
parts.append(build_skills_section(skills))
|
||||
if condition_vars:
|
||||
parts.append("")
|
||||
parts.append(build_triggers_section(triggers or [], condition_vars))
|
||||
parts.append(build_triggers_section(triggers or [], condition_vars, condition_funcs))
|
||||
if cold:
|
||||
parts.append("")
|
||||
parts.append(build_cold_memory_section(cold))
|
||||
|
||||
Reference in New Issue
Block a user