Diagnostic-Einstellungen fuer FLUX:
- Default-Modell (dev | schnell) — wird via RVS gepusht, flux-bridge
hot-swappt die Pipeline aus dem HF-Cache (~15-30s)
- Raw-Keyword (Default 'flux') — Pipe-Modus, Brain leitet Stefans Text
1:1 als prompt durch, kein Rewriting/Beautify
- Switch-Keyword (Default 'fix') — zwingt das ANDERE Modell als Default
Brain-Tool flux_generate um model + raw erweitert, System-Prompt-Block
mit den aktuellen Diagnostic-Settings + Whisper-Toleranz-Hinweis.
Kein eager Bootstrap-Load: flux-bridge wartet auf config oder ersten
Request. Bei erstem HF-Download zeigt Banner "laedt erstmalig runter"
mit Pfeil-Icon, Toast in der App wenn fertig.
FLUX_MODEL aus der .env entfernt (Steuerung jetzt komplett ueber
Diagnostic). HF_TOKEN-Kommentar erklaert warum trotz lokaler Inference
noetig (HF Gate-Mechanismus fuer FLUX.1-dev).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Eigener Compose-Stack im /flux Verzeichnis (kann auf separater Maschine
laufen). aria-bridge routet flux_request via RVS, ARIA referenziert das
fertige PNG im Reply mit [FILE: ...]-Marker. Brain-Tool flux_generate
mit Caps fuer steps/dimension.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stefan: bei aktuellen near()-Watcher gibt's nur "solange drin". Reale
Szenarien wollen aber differenzieren:
- VORWARNUNG vor Ziel (Blitzer-Warner 2 km vorher) → entered_near mit grossem r
- ANKUNFT exakt am Ziel → entered_near mit kleinem r
- VERLASSEN (Parkplatz, hast du was vergessen) → left_near
- KONTINUIERLICH-DRIN (bin noch in der Naehe?) → near (Default, throttled)
Zwei neue Funktionen in der Condition-Whitelist:
- entered_near(lat, lon, r): True NUR im Moment des Uebergangs
draussen → innen. Fires einmal pro Eintritt.
- left_near(lat, lon, r): True NUR im Moment des Uebergangs innen →
draussen. Fires einmal pro Austritt.
State-Tracking:
- pro Trigger pro near-Aufruf wird der letzte Auswertungs-Wert (true/
false) im Watcher-Manifest gespeichert (Field "near_states", Key
"lat.6,lon.6,radius"). Background-Loop liest's vor dem Eval, gibt's
per collect_variables(prev_near_states=...) in die Closure, schreibt
nach dem Eval die neuen Werte zurueck — UNABHAENGIG ob gefeuert
wurde, sonst greift die Uebergangs-Erkennung nicht.
Background _tick:
- Aufteilung in Watcher-Pass (mit prev_near_states pro Trigger) und
Timer-Pass (ohne State, gemeinsame vars). Bisher war collect_variables
einmal pro Tick — jetzt einmal pro Watcher. Disk-Stats sind teuer
aber unter 30 Watchern unkritisch; bei mehr koennen wir cachen.
ARIA-Tool-Description erweitert (trigger_watcher): erklaert die drei
Modi mit Use-Cases und empfohlenen Throttle-Werten (kurz fuer entered/
left, lang fuer near).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Etappe 1 von Stefans App-Memory-UX-Wunsch:
Brain agent.py: memory_save Dispatcher pushed jetzt action="created",
memory_update Dispatcher pushed action="updated" mit demselben
memory_saved-Event-Typ. Bridge reicht das action-Feld im Payload mit
durch (in beiden Side-Channel-Pfaden — send_to_core + trigger-fired).
App ChatScreen: ChatMessage.memorySaved.action ('created' | 'updated'
| 'deleted'). Bubble-Header je nach Aktion:
- created → "🧠 ARIA hat etwas gemerkt" (gelb)
- updated → "🧠 ARIA hat eine Notiz geändert" (gelb)
- deleted → "🧠 ARIA hat eine Notiz gelöscht" (rot)
Naechste Etappen folgen (Detail-Modal beim Tap, Edit + Anhang-Upload,
Notizen-Inbox neben Lupe, Memory-Editor in Settings).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug-Report von Stefan: er hat im Diagnostic den Baujahr-Memory von
1972 auf 1974 geaendert, ARIA wusste das nicht und beharrte auf 1972
(weil ihr letzter Conversation-Turn noch '1972' enthielt). Sie konnte
auch nicht nachpruefen, sagte selbst: "Qdrant kann ich nicht aktiv
durchsuchen".
Fix: zwei neue Meta-Tools im agent.py.
memory_search(query, mode='text'|'semantic', k=5):
- Volltext oder semantic via store.search_text / store.search
- Liefert Liste mit Titel, ID, Content, Anhaengen
- Tool-Description sagt explizit: "Memory ist Truth ueber dem
Conversation-Window" — wenn beide unterschiedlich sind, gilt
Memory. Plus Anker-Anwendungsfaelle: 'schau in deinem Gedaechtnis',
'ich hab das aktualisiert', 'pruef ob's schon was zum Thema gibt'
memory_update(id, title?, content?, category?, tags?, pinned?):
- Patch existierender Memory per ID (aus memory_search oder Cold-Memory)
- Content-Change triggert Re-Embedding fuer Search, sonst nur
Payload-Update
- Pushed memory_saved-Event analog zu memory_save (App/Diagnostic
refreshen)
- Tool-Description empfiehlt explizit Update statt neuem Save bei
Korrekturen/Ergaenzungen — vermeidet Fragmentierung
Damit kann Stefan jetzt sagen "schau in deinem Gedaechtnis" und ARIA
findet den aktualisierten Eintrag. Plus bei spaeteren Korrekturen
("ach nee, 1974") nutzt ARIA memory_update statt memory_save +
hinterlaesst einen sauberen Eintrag.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Letzter Baustein vor Stefan's End-to-End-Test:
memory_attachments.attach_from_path(memory_id, src_path):
- Kopiert eine bestehende Datei aus /shared/uploads/ oder
/shared/memory-attachments/ in das Anhang-Verzeichnis der Memory
- Pfadschutz: nur ALLOWED_SOURCE_PREFIXES (/shared/uploads/,
/shared/memory-attachments/) — kein Zugriff auf Root-FS oder
SSH-Keys
- Groessen-Limit wie save_attachment (20 MB Default)
agent.py memory_save:
- Neuer optionaler Parameter `attach_paths: List[str]`
- Nach dem upsert: pro Pfad attach_from_path → Payload update mit
neuen Anhang-Metadaten
- Fehler beim Anhang sind nicht fatal (Memory bleibt gespeichert,
Hinweis in der Tool-Response)
- Tool-Description deutlich erweitert: expliziter Workflow-Hinweis
bei Bildern → erst `Read <pfad>` aufrufen (Claude Code Read ist
multi-modal), Texte/Kennungen/Marken in den content extrahieren,
dann erst memory_save mit attach_paths. Beispiel-Workflow als
Pseudocode mit Cessna 172 / Kennung D-EAAA.
End-to-End-Workflow ist jetzt einarmig moeglich:
User: "Ich hab eine Cessna 172" + Bild im Attachment
ARIA: Read /shared/uploads/aria_xy.jpg → sieht "Kennung D-EAAA"
ARIA: memory_save(content="Stefan besitzt eine Cessna 172,
Kennung D-EAAA, weiss/rot lackiert.",
attach_paths=["/shared/uploads/aria_xy.jpg"])
→ 🧠-Bubble mit Anhang in der App
→ Spaetere Frage "welche Kennung hat mein Flieger?" liefert via
Cold-Memory den Eintrag inkl. Kennung aus dem content
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stufe C — App:
- ChatMessage.memorySaved.attachments [{name, mime, size, path, localUri}]
- memory_saved-Listener uebernimmt payload.attachments
- renderMessage memorySaved-Bubble zeigt Anhaenge als Tap-Reihen
(Icon 🖼/📄 + Filename + Hint). Tap → file_request via Bridge,
beim ersten Mal "(tippen zum Laden)" → nach file_response cached
+ bei Bildern setFullscreenImage, bei anderen openFileWithIntent
- file_response-Handler updated zusaetzlich memorySaved.attachments
per serverPath-Match
- Styles fuer memoryAttachmentRow/Icon/Name/Meta
Stufe D — System-Prompt:
- prompts._attachments_line: pro Memory eine Zeile
"📎 Anhaenge: foo.jpg (image/jpeg, 109 KB) — Pfad: /shared/memory-attachments/<id>/"
- Wird in build_hot_memory_section + build_cold_memory_section
nach dem Content angehangen
- ARIA "weiss" damit dass Anhaenge da sind und kann via Bash darauf
zugreifen (file, head, base64 …). Echt sehen kann sie sie erst mit
Multi-Modal-Pipeline (Stufe E)
- memory_save Dispatcher: attachments-Liste auch im memory_saved-Event
(vermutlich [] beim Save, aber konsistent fuer spaeteres
Speichern-mit-Anhaengen-Pattern)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: Agent.chat() rief store.search() OHNE score_threshold — die
Top-5 wurden ungefiltert in den 'Moeglicherweise relevant'-Block
des System-Prompts gepackt. Bei kleiner DB hatte das absurde Folgen:
Stefan fragte 'hab ich ein flugzeug?', Cold-Search lieferte Top-1
'Watcher-Latenzproblem' mit Score 0.138 + 'Firmenadresse' mit 0.094,
ARIA wob die Firmenadresse in die Antwort ein ('Die Adresse habe ich
aus meinem Gedaechtnis...') — obwohl der User gar nicht danach gefragt
hat.
Fix: Konstante COLD_SCORE_THRESHOLD=0.30 in Agent eingefuehrt und an
store.search() durchgereicht. Treffer unter 0.30 werden als Rauschen
verworfen, ARIA bekommt nur substantielle Memories ins Cold-Set.
Konsistent mit dem Threshold im /memory/search HTTP-Endpoint und dem
Diagnostic UI.
MiniLM-multilingual gibt fuer unverwandte deutsche Texte gerne 0.10-
0.25 Score — alles darunter ist Embedder-Noise, kein echter Bezug.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ARIA hatte beim 'weisst du ob ich ein Flugzeug habe?'-Test richtig
geantwortet ('nein'), aber transparent erklaert dass sie das Wort
'Cessna' aus dem memory_save Tool-Description kennt — wo es als
Beispiel fuer den fact-Type stand. Ein Beispiel-Text der jedes
Chat-Turn im System-Prompt landet ist suboptimal, auch wenn ARIA
ihn korrekt einordnet.
Fix: das konkrete Beispiel durch eine generische Aufzaehlung
ersetzt (Vorlieben/Besitz/Orte/Termine/Personen). Ohne Stefan-
spezifisches Phantom-Wissen. Selber Spirit in der search-text
Docstring im main.py (geht zwar nicht in den Prompt, aber lieber
konsistent).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ARIA hatte bisher KEIN Tool um eigene Notizen sauber zu persistieren —
sie ist deshalb aufs Claude-Code-File-Memory ausgewichen (das wir mit
dem letzten Commit per tmpfs abgeklemmt haben). Jetzt schliesst sich
der Loop: ein echtes memory_save-Tool gegen die Qdrant-DB.
Brain:
- agent.py: memory_save als Meta-Tool mit Schema (title, content,
type, optional category/tags/pinned). Tool-Description erklaert
die Type-Wahl (identity/rule/preference/tool/skill = pinned,
fact/conversation/reminder = cold) und sagt explizit: "Du hast
KEIN File-Memory mehr, schreibe nicht in ~/.claude/projects/..."
- Dispatcher: validiert type-enum, ruft self.embedder.embed +
self.store.upsert, pushed memory_saved als _pending_events damit
Bridge eine Bubble broadcasten kann.
Side-Channel-Pipeline (gleich wie skill_created/trigger_created):
- Bridge send_to_core + _handle_trigger_fired: forwarden
memory_saved als RVS-Event
- rvs/server.js: ALLOWED_TYPES += memory_saved
- diagnostic/server.js: relayed memory_saved von RVS an Browser
- diagnostic UI: addMemorySavedBubble (gelber Border) + Auto-Refresh
des Gehirn-Tabs wenn aktiv
- android: ChatMessage.memorySaved-Feld, Listener fuer memory_saved,
renderMessage-Spezialbubble, History-Replace-Schutz (lokal-only)
Damit ist die Architektur konsistent:
"merk dir X" → ARIA ruft memory_save → Eintrag in Qdrant →
Diagnostic-Gehirn-Tab zeigt's sofort → bei naechstem Turn liefert
Cold Memory (Semantic Search) das Wissen wieder rein.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ARIA wusste nicht wieviel Uhr es ist (kein Bash, kein Time-Tool, kein
Timestamp im System-Prompt) und konnte fires_at als ISO-UTC schlicht
nicht ausrechnen. Zwei Fixes:
1. prompts.py: build_time_section() injiziert UTC + lokale Zeit
(Europa/Berlin Sommer/Winter-Heuristik) als '## Aktuelle Zeit'-Block
oben in den System-Prompt. Hilft auch beim Einordnen von
Watcher-Conditions wie hour_of_day == 8.
2. agent.py trigger_timer-Tool: neuer Parameter `in_seconds` als
Alternative zu fires_at. Bei relativen Angaben ('in 2 Minuten')
rechnet jetzt der Server den absoluten Timestamp aus — keine
Rechnerei in der LLM noetig. fires_at bleibt fuer feste Termine.
required nur noch name + message.
Diagnostic-API (/triggers/timer) bleibt absolute-only, da der Browser
selbst datetime hat.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ARIA kann jetzt GPS-Watcher mit near() effektiv nutzen: die App liefert
kontinuierliche Position, Brain wertet sie in den Background-Triggers aus.
rvs/server.js
ALLOWED_TYPES: location_update (App→Bridge) + location_tracking (Brain→App).
bridge/aria_bridge.py
location_update Handler: persistiert {lat, lon} via _persist_location in
/shared/state/location.json — selber Pfad wie chat/audio-events, aber als
eigenes Event ohne Chat-Overhead.
aria-brain/agent.py
Neues Meta-Tool request_location_tracking(on, reason). Dispatcher fuegt
{type: "location_tracking", on, reason} zu _pending_events hinzu →
Bridge forwarded als RVS-Message zur App.
aria-brain/prompts.py
Trigger-Section bekam neuen Block "GPS-Watcher mit near()": ARIA wird
angewiesen request_location_tracking(on=true) zu rufen wenn sie einen
near()-Watcher anlegt, und wieder false beim Loeschen des letzten.
android/src/services/gpsTracking.ts (NEU)
Singleton-Service. start(reason) → Geolocation.watchPosition mit
distanceFilter 30m + interval 15s, sendet location_update an RVS.
stop(reason) → clearWatch. Persistiert Status in 'aria_gps_tracking',
restoreFromStorage() beim Settings-Mount. Permission-Request fuer
ACCESS_FINE_LOCATION + Toast-Benachrichtigung bei An/Aus.
android/src/screens/SettingsScreen.tsx
Neuer Switch im "Standort"-Block: "GPS-Tracking (kontinuierlich)" mit
Hinweis-Text. Subscribe auf gpsTrackingService.onChange damit Toggle
reflektiert wenn ARIA das per Tool umschaltet.
RVS-Handler: location_tracking → gpsTrackingService.start/stop mit
Reason aus Brain-Tool.
Ablauf Stefan→ARIA→Blitzer:
1. Stefan: "Warn mich vor Blitzern auf Route nach Rhauderfehn"
2. ARIA: skill_create("blitzer-warner") falls noch nicht da
3. ARIA: run_blitzer-warner → Liste {lat,lon,name}
4. ARIA: pro Eintrag trigger_watcher mit near(lat,lon,500)
5. ARIA: request_location_tracking(on=true, reason="Blitzer-Warner aktiv")
6. App: GPS-Tracking startet, sendet alle 15s location_update
7. Bridge: /shared/state/location.json wird aktuell gehalten
8. Brain-Background-Loop: alle 30s near()-Check pro Trigger
9. Bei Erfolg: ARIA spricht "Blitzer A31 km 12 in 500m"
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
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>