From 7b46881677a4be71ed733499328fd22f814c0858 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sat, 3 Oct 2026 10:21:50 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20README=20auf=20den=20aktuellen=20Stand?= =?UTF-8?q?=20=E2=80=94=20Android-Agent,=20Jellyfin,=20OpenAI-Endpunkt,=20?= =?UTF-8?q?Phase=20C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die README war auf dem Stand vom 24.09. Seitdem sind ~60 Commits dazugekommen, von denen ganze Baustellen gar nicht auftauchten. Neu dokumentiert: - Android-Agent 📱📺 (eigener Abschnitt): eine APK fuer Handy und Fire TV — sehen, steuern, ausgeben (Overlay + ARIAs echte Stimme), Audio-Fokus, Sprachdialog, Turn-Ownership im Broadcast-Relay, fester Signaturschluessel, Ausrollen per Satellit via ADB inkl. Fern-Provisionierung - GUI-Steuerung der Desktop-Host-Agenten (capability-gated) - Jellyfin-Integration (mehrere Server, API statt Klick-Weg) - OpenAI-Endpunkt fuers lokale LLM + openhands-Profil, inkl. der Regel ".env gewinnt immer -> Diagnostic-Felder nur lesend" - Agent-Historie und Auslastungs-Monitor in der Diagnostic - App: Teilen-Ziel, Sprachnachricht zu Anhaengen, Zwischenruf per Sprache - Trigger: Projekt-Kontext + ehrlicher Zustand in trigger_list - Roadmap "Phase C" samt der fuenfteiligen Ursachenkette hinter den verlorenen Sprachnachrichten — jede Ursache sah fuer sich plausibel aus, das ist dokumentationswuerdig Korrigiert (waren schlicht falsch): - "Bildanalyse eingeschraenkt, ARIA sieht den Dateipfad, nicht das Bild" — widersprach der eigenen Roadmap; Vision laeuft - "Grosse Dateien >5MB koennen WebSocket-Limits ueberschreiten" — die echten Grenzen sind jetzt 1500 MB Transport, 25 MB Auto-Download, 64 MB auf Tipp - Audio-Format: Live-PCM-Streaming ist der Normalweg, AAC/MP4 nur noch Fallback Neu als Limitierung benannt, weil heute gefragt: die Sprachaufnahme ist NICHT wiederaufsetzbar — ein Verbindungsabbruch mitten in der Aufnahme verliert das Stueck, es wird nicht gepuffert. Gleiches gilt fuer die TTS-Richtung. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 176 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 01b7cfd..ed34f70 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ ARIA hat zwei Rollen: | Compute-Node(s) (STT/TTS/LLM) | 1..n GPU-Rechner | `cd xtts && cp .env.example .env && docker compose up -d` | | Satellit(en) 🛰️ (optional) | Fremdes Netz (Büro …) | `cd satellite && cp .env.example .env && docker compose up -d --build` | | Host-Agent(en) 💻 (optional) | Direkt auf einem Rechner | `cd host-agent && ./build.sh` → Binary + `.env` auf den Rechner, starten (Details unten & in [`host-agent/README.md`](host-agent/README.md)) | +| Android-Agent 📱📺 (optional) | Handy, Tablet, Fire TV | `cd host-agent/android && ./build.sh` → APK, oder per Satellit via ADB ausrollen (Details unten) | | Android App | Stefans Handy | APK installieren (Auto-Update via RVS) | > Compute-Nodes sind optional: ohne sie faellt STT auf lokales Whisper (CPU, @@ -482,11 +483,18 @@ Erreichbar unter `http://:3001`. Teilt das Netzwerk mit der Bridge. Sicherer Condition-Parser via Python `ast` (Whitelist, kein `eval`). Der System-Prompt enthaelt zusaetzlich einen `## Aktuelle Zeit`-Block (UTC + Europa/Berlin) damit ARIA Timer-Zeitpunkte korrekt setzen kann. **Auflösung**: Background-Loop tickt alle 8s (vorher 30s — bei 100 km/h durch einen 300m-Radius war eine Vorbeifahrt nur ~22s drin und konnte verpasst werden). Plus event-getrieben: Bridge ruft nach jedem `location_update` von der App sofort einen `/triggers/check-now` im Brain — Watcher sehen die frische Position in Millisekunden statt im Polling-Takt. `near()`-Funktionen ignorieren GPS-Daten älter als 5 Minuten (verhindert Phantom-Fires bei abgeschaltetem Tracking). + + **Projekt-Kontext**: ein Trigger merkt sich das Projekt, in dem er angelegt wurde (`project_id`), und die Antwort kommt beim Feuern **dort** zurueck. Ohne das landete jede Trigger-Antwort im Hauptchat — im Projekt-Thread blieb es still, und es sah aus wie „der Timer hat nicht gefeuert". + + **Zustand ehrlich**: ein One-Shot-Timer wird nach dem Feuern automatisch deaktiviert. `trigger_list` zeigt darum ausdruecklich `SCHON GEFEUERT (Nx, zuletzt )` statt nur „DEAKTIVIERT" — sonst sind „hat sauber gefeuert" und „war nie an" nicht unterscheidbar, und ARIA berichtet guten Glaubens das Falsche. +- **Integrationen → Jellyfin**: beliebig viele Server (`+`-Button) mit URL + API-Key. ARIA steuert die Wiedergabe ueber die **API** (`jellyfin_search` / `jellyfin_devices` / `jellyfin_play` / `jellyfin_control`) statt sich per `ui_tap` durch die Oberflaeche zu klicken — schneller und zuverlaessiger. Eine eingeschlafene Sitzung erkennt ARIA selbst und baut sie neu auf. - **Dateien**: Browser fuer `/shared/uploads/` mit Multi-Select + "Alle markieren" + Bulk-Download (ZIP bei 2+) + Bulk-Delete. Live-Update der Chat-Bubbles beim Delete. - **Einstellungen**: Reparatur (Container-Restart fuer Brain/Bridge/Qdrant), Komplett-Reset, Betriebsmodi, Sprachausgabe + Voice-Cloning + F5-TTS-Tuning + Voice Export/Import, **FLUX Bildgenerierung** (Default-Modell + Raw/Switch-Keywords + HF-Token), **OAuth-Apps** (Spotify Default, alle anderen Provider per ARIA on-demand oder "+ Custom"-Button mit auth_url/token_url/scopes) mit client_id+client_secret pro Service + One-Click-Autorisieren + Service-Loeschen, Whisper, Sprachmodell (brainModel), Onboarding-QR, App-Cleanup ### Was zusaetzlich noch drin steckt +- **Agent-Historie** (Satelliten → Host-Agenten): pro Agent eine aufklappbare Historie der Befehle und Screenshots, gruppiert **pro User-Nachricht** — man sieht, welche Geraete-Aktionen zu welcher Frage gehoerten. Brain schickt dafuer je Host-Aktion ein `agent_history`-Event; die Bridge haelt es und antwortet auf `agent_history_query`. +- **Auslastungs-Monitor** pro Compute-Box: Klick auf „Auslastung" zeigt **live `nvidia-smi`** (1s-Takt) plus zwei Verlaufs-Graphen (GPU-Last und Token-Verbrauch, 15s-Sampling, Ringpuffer ~2h) und ein Besen-Symbol zum Zuruecksetzen. Die **Historie liegt auf der Box**, nicht im Diagnostic — abgeholt per RVS (`node_stats_*`), kein SSH und kein Docker-Socket noetig. - **Disk-Voll Banner** mit copy-baren Cleanup-Befehlen (safe + aggressiv) - **Token/Call-Metrics**: pro Claude-Call ein Eintrag in `/data/metrics.jsonl` mit ts + Token-Schaetzung. Gehirn-Tab zeigt 1h/5h/24h/30d-Aggregat plus Progress-Bar gegen Plan-Limit (Pro / Max 5x / Max 20x / Custom). Warn-Schwelle 80%, kritisch 90%. - **Voice Cloning**: Audio-Samples hochladen, Whisper transkribiert den Ref-Text automatisch @@ -514,6 +522,9 @@ Erreichbar unter `http://:3001`. Teilt das Netzwerk mit der Bridge. - **Wake-Word** (on-device, openWakeWord ONNX): "Hey Jarvis", "Alexa", "Hey Mycroft", "Hey Rhasspy" — Mikrofon hoert passiv mit, Konversation startet beim Schluesselwort. Komplett on-device via ONNX Runtime, kein API-Key, kein Cloud-Roundtrip, Audio verlaesst das Geraet nicht. - **VAD (Voice Activity Detection)**: Adaptive Schwelle (Baseline aus ersten 500ms Mic-Pegel + 6dB Offset). Konfigurierbare Stille-Toleranz (1.0–8.0s, Default 2.8s) bevor Auto-Stop greift. Max-Aufnahme einstellbar (1–30 min, Default 5 min) - **Nachricht anstellen statt abbrechen** (Queue pro Projekt): Schickst du eine zweite Nachricht waehrend ARIA noch am aktuellen Task arbeitet, wird sie **angestellt** statt den laufenden abzubrechen — laeuft der Reihe nach, pro Projekt unabhaengig. Wartende zeigen als `⏸`-Bubble (tippen entfernt sie aus der Warteschlange). Explizites Abbrechen laeuft ueber den Stop-Button am „ARIA denkt". Eine neue Sprachnachricht stoppt nur akustisch das TTS (sauberes Mikro), bricht die laufende Arbeit aber nicht mehr ab +- **Zwischenruf** (📣): schiebt eine Korrektur in den **laufenden** Turn statt sie anzustellen — ohne Abbruch. Erscheint, sobald ARIA im Kontext arbeitet. Mit Text im Feld geht er sofort raus; **ohne Text schaltet er die naechste Aufnahme scharf**, dann geht der Zwischenruf per Sprache. Der laufende Turn wird dabei nicht gecancelt, nur die Wiedergabe gestoppt (sonst redet ARIA ins offene Mikro) +- **Sprachnachricht zu Anhaengen**: Bild anhaengen und den Auftrag dazu **sprechen** statt tippen. Die Dateien gehen beim Antippen des Mikros sofort hoch (Upload laeuft parallel zum Reden); die Bridge fuehrt Anhang und gesprochenen Satz ueber die `clientMsgId` zu **einem** Turn zusammen und legt beides in **eine** Bubble. Ohne das sah ARIA ein Bild ohne Auftrag und danach einen Satz ohne Bild. Das Mikro ist darum immer sichtbar — auch mit Anhang oder getipptem Text +- **Teilen-Ziel** (Android-Share): „Teilen → ARIA" aus WhatsApp, Galerie, Browser … → Dialog zeigt *was* geteilt wurde, dann *wohin* (Projekt oder Hauptchat), dann optional ein Text dazu (darf leer bleiben). Die native Seite kopiert die Dateien sofort in den App-Cache, weil die Leseerlaubnis einer `content://`-URI nur fuer diesen Intent gilt und nach der Projektauswahl schon erloschen waere - **Rueckfrage-Loop**: Stellt ARIA eine echte, blockierende Rueckfrage, **pausiert** die Queue und deine naechste Eingabe beantwortet sie — bis eine finale Antwort kommt, dann laeuft der naechste Queue-Eintrag (gleiches Muster). Banner „❓ ARIA fragt nach — deine Eingabe beantwortet das". ARIA signalisiert das ueber einen unsichtbaren `[[AWAIT]]`-Marker im Antworttext (das Modell deklariert den Zustand selbst, kein „endet-mit-?"-Raten; Brain strippt ihn und gibt `awaiting_reply` an App + Diagnostic durch) - **Pro-Projekt-Textfeld-Entwuerfe**: Der Feldinhalt bleibt beim Projektwechsel erhalten — in Projekt X tippen, zu Y wechseln (leeres Feld), zurueck zu X → dein Entwurf steht wieder da. Persistiert ueber Neustart. Gleiches Verhalten im Diagnostic - **Wake-Word waehrend TTS**: Du kannst "Computer" sagen waehrend ARIA noch redet — AcousticEchoCanceler verhindert dass ARIAs eigene Stimme das Wake-Word triggert @@ -819,6 +830,24 @@ Jeder Dienst haengt an einem Compose-Profil. Ein Node startet ueber | `whisper` | aria-whisper-bridge | STT-Fallback (faster-whisper CUDA) | | `f5tts` | aria-f5tts-bridge | TTS (F5-TTS Voice Cloning) | | `llm` | aria-llama-swap + llm-adapter| Lokales LLM (llama-swap, OpenAI-kompat.) | +| `openhands`| aria-openhands | OpenHands gegen das lokale LLM (optional) | + +#### OpenAI-Endpunkt fuers lokale LLM + +Das lokale LLM ist zusaetzlich als **OpenAI-kompatibler Endpunkt** erreichbar — +damit laesst sich z.B. OpenHands oder jedes andere OpenAI-SDK darauf richten. +Port und Key kommen aus der `.env` der Box (`LLM_OPENAI_PORT`, +`LLM_OPENAI_API_KEY`, siehe `xtts/.env.example`). + +> **Die `.env` gewinnt immer.** Steht der Wert dort, sind die Felder in der +> Diagnostic **nur lesend** — sonst traegt man dort etwas ein, es wirkt nach dem +> naechsten Container-Start nicht, und niemand versteht warum. Ist in der `.env` +> nichts gesetzt, laesst sich der Key pro Box in der Diagnostic pflegen +> (`llm_openai_config`). + +Der Port ist ein Docker-Port-Mapping und darum **nie** aus der Diagnostic +aenderbar. Zur Absicherung nach aussen: SSH-Tunnel statt den Port im LAN +aufzureissen (Details in [`xtts/README.md`](xtts/README.md)). ### Architektur (Aufteilung auf mehrere Nodes) @@ -1004,6 +1033,92 @@ keine offenen Ports; alle Kommandos werden geloggt. Gibt **vollen** Rechnerzugri > Sichtbar in der Diagnostic unter **Satelliten → Host-Agenten 💻**. +### GUI-Steuerung (Desktop) + +Auf Linux/Windows/macOS kann der Agent zusaetzlich die **grafische Oberflaeche** +bedienen (`host_ui_tap` / `host_ui_text` / `host_ui_swipe` / `host_ui_key` / +`host_app_launch`). Das ist **capability-gated**: der Agent meldet beim +`host_hello` nur, was er wirklich kann — auf einem Linux-Server ohne X/Wayland +fehlt die GUI-Faehigkeit einfach in der Liste, und ARIA sieht das. Eingabe-Weg +je System: `windows` · `macos` · `xdotool` (X11) · `ydotool` (Wayland). + +--- + +## Android-Agent 📱📺 — Handy, Tablet, Fire TV + +Dieselbe APK laeuft auf **Handy/Tablet** und auf **Fire TV / Android TV** +(`host-agent/android/`). Sie ist das Android-Gegenstueck zum Host-Agenten: +ausgehende Verbindung zum RVS, kein offener Port, erscheint in der Diagnostic +unter **Satelliten → Host-Agenten 💻**. + +**Sehen** — Screenshot (MediaProjection) und Bildschirm-Inhalt als Struktur +(`ui_dump` via Accessibility-Service, nur lesend). Beides geht auch bei +gesperrtem Geraet. + +**Steuern** — `ui_tap` / `ui_text` / `ui_swipe` / `ui_key` / `app_launch` ueber +den Accessibility-Service. **Nur bei entsperrtem Geraet** — Android laesst +Gesten auf dem Sperrbildschirm nicht zu; der Agent sagt das klar, statt stumm +nichts zu tun. Auf dem Fire TV gibt es keinen Touchscreen, dafuer das D-Pad. + +**Ausgeben** (v.a. Fire TV, dort ist ARIA ein echter Endpunkt): + +| Weg | Was passiert | +|-----|--------------| +| Einblendung | Text ueber dem laufenden Bild (Overlay, braucht „Ueber anderen Apps anzeigen") | +| Sprache | ARIAs **echte** Stimme — der Agent fordert das Audio per `tts_request` ueber den normalen F5-TTS-Pfad an und spielt das PCM ab | +| Einstellung | Overlay oder Sprache als Standard, pro Anfrage ueberschreibbar (`mode`) | + +> Fire TV Sticks haben oft **keine deutsche TTS-Engine**. Darum laeuft die +> Sprachausgabe bewusst nicht ueber die Geraete-Stimme, sondern ueber ARIAs +> eigene. Die Geraete-Stimme gibt es nur noch auf ausdrueckliche Anforderung +> (`engine=device`). + +**Audio-Fokus** — bevor ARIA redet, wird der laufende Film leiser (`duck`) oder +angehalten (`pause`); danach laeuft er weiter. Sonst redet ARIA mitten in +Netflix hinein und man versteht beides nicht. + +**Sprachdialog** — der Agent kann auch *zuhoeren* (`listen` / `listen_stop`) und +streamt das Mikrofon mit demselben Protokoll wie die App +(`stt_stream_start` → `stt_audio_chunk` → `stt_stream_end`). + +> **Turn-Ownership:** der RVS ist ein Broadcast-Relay ohne Adressierung — jeder +> Client im Raum bekommt jede Antwort. Ohne Filter wuerden Handy und Fire TV +> dieselbe Antwort gleichzeitig vorlesen. Jedes Geraet gibt darum nur aus, was +> aus *seiner* eigenen Frage entstanden ist (`audioRequestId` → `messageId`). + +### Bauen + ausrollen + +```bash +cd host-agent/android && ./build.sh # Docker (Android-SDK + Gradle) +# -> dist/aria-android-agent.apk + +# Release mit allen Agent-Artefakten (Linux/Windows/Android) als Gitea-Assets: +cd host-agent && ./release_agent.sh 0.0.1.4 +``` + +Der Signaturschluessel liegt fest in `host-agent/android/aria-agent.keystore` +(gitignored). Ohne ihn bekaeme jeder Build einen neuen Debug-Key, und Android +verweigert die Installation mit *„Konflikt mit einem bestehenden Paket"* statt +zu aktualisieren. + +### Ausrollen per Satellit (ohne Kabel, ohne Abtippen) + +Ein Satellit im selben Netz kann Android-Geraete per **ADB over Network** +bespielen — besonders fuer den Fire TV, wo QR-Code-Scannen nicht geht: + +``` +Diagnostic → Satelliten → Geraet → „Agent ausrollen" +``` + +Der Satellit verbindet per ADB (Port 5555, wartet auf die Bestaetigung am +Geraet — ein Klick genuegt), installiert die APK, erteilt die Berechtigungen per +`appops`/`pm grant` und **provisioniert die RVS-Zugangsdaten per Intent** — man +tippt am Fernseher nichts ein. Ein schon vergebener Geraetename wird dabei +vorgeschlagen; nur wenn es keinen gibt, kommt der automatisch generierte. + +> Die Berechtigungen bleiben ueber Neustarts erhalten; die Bildschirm-Aufnahme +> schaltet sich nach einem Reboot selbst wieder scharf. + --- ## Docker Volumes @@ -1073,14 +1188,28 @@ docker exec aria-brain curl localhost:8080/memory/stats `Hey Rhasspy` funktionieren sofort, eigene Wake-Words muessen aktuell noch als `.onnx`-Datei ins App-Bundle gelegt + zur Liste in `wakeword.ts` hinzugefuegt werden. Die Diagnostic-Upload-UI ist Phase 2. -- **Audio-Format**: App nimmt AAC/MP4 auf, Bridge konvertiert via FFmpeg zu 16kHz PCM. +- **Audio-Format**: Die App streamt live 16 kHz mono s16le an die STT-Bridge + (`stt_stream_start` → `stt_audio_chunk` → `stt_stream_end`). Der alte Weg + (AAC/MP4 aufnehmen, Bridge konvertiert per FFmpeg) existiert noch als Fallback. +- **Sprachaufnahme ist nicht wiederaufsetzbar**: Die Audio-Chunks gehen live + raus. Bricht die Verbindung mitten in der Aufnahme ab, fehlt dieses Stueck — + es wird nicht gepuffert und nicht nachgeschickt. Gleiches gilt fuer die + Sprachausgabe: F5-TTS streamt saetzeweise PCM, ein Abbruch verliert den Rest. + Lokal aufnehmen + wiederaufsetzbar hochladen (Queue mit Teil-Uebertragung) + waere der naechste Schritt, ist aber noch nicht gebaut. - **RVS Zombie-Connections**: WebSocket-Verbindungen sterben gelegentlich ohne Fehlermeldung. Bridge hat Ping-Check (5s), Diagnostic nutzt frische Verbindungen pro Request. -- **Bildanalyse eingeschraenkt**: Bilder werden in `/shared/uploads/` gespeichert. ARIA kann - sie per Bash/Read-Tool oeffnen, aber Claude Vision (direkte Bildanalyse) ist ueber den - Proxy-Pfad (`claude --print`) noch nicht moeglich. ARIA sieht den Dateipfad, nicht das Bild. -- **Dateigroesse**: Grosse Dateien (>5MB) koennen WebSocket-Limits ueberschreiten. - Bilder werden in der App auf max 1920x1920px @ 80% Qualitaet komprimiert. + App-seitig fragt die Aufnahme-Sperre den Socket statt den gemerkten Zustand. +- **Dateigroesse**: Der RVS und alle Worker fahren `max_size` 1500 MB (≈1 GB + binaer plus base64-Overhead); groessere Dateien weist die Bridge aktiv ab, + statt die Verbindung reissen zu lassen. Die App holt ueber **25 MB** nichts + mehr ungefragt nach und bremst beim ausdruecklichen Antippen bei **64 MB** — + base64-in-JSON muss komplett in den Speicher, und ein 150-MB-Video hat das + Handy per OOM umgebracht. Bilder werden in der App auf max 1920x1920px @ 80% + Qualitaet komprimiert. +- **Lautstarke Umgebung stoert die STT**: Laute Musik im Raum verschlechtert die + Erkennung messbar. Bewusst akzeptiert — Wake-Wort-Bestaetigung und der + Silero-Endpoint stehen als Opt-in bereit. --- @@ -1190,6 +1319,47 @@ docker exec aria-brain curl localhost:8080/memory/stats - [x] **Bridge-Hang-Schutz + Voice-Speed persistent**: 3-Schichten-Watchdog (TCP-Keepalive + Asyncio-Watchdog + File-Based Liveness mit Self-Kill), TLS-Fallback klebt nicht mehr beim Reconnect. `xttsSpeed` jetzt im voice_config.json persistiert — greift auch bei Diagnostic-Chats und nach Bridge-Restart - [x] **Bubble-Aktionen in der App**: Long-Press oder ⎘-Icon auf einer Chat-Bubble → Aktions-Menu mit "📋 Ganzen Text teilen" plus pro extrahierte URL/E-Mail/Telefonnummer eine eigene Teilen-Option (System-Share-Sheet → Zwischenablage / Apps / Browser) +### Phase C — ARIA greift auf echte Geraete durch (09–10/2026) + +- [x] **Host-Agenten** (Linux/Windows/macOS): Standalone-Binary, ausgehend zum RVS, steuert den Rechner auf dem es laeuft. Windows-Build per Docker+Wine samt `setup.exe` (NSIS + nssm) das einen Dienst installiert und seine `.env` aus ProgramData liest. Plus **GUI-Steuerung** capability-gated (`windows`/`macos`/`xdotool`/`ydotool`) — ein Server ohne X meldet die Faehigkeit einfach nicht +- [x] **Android-Agent** (eine APK fuer Handy + Fire TV): sehen (Screenshot via MediaProjection, `ui_dump` via Accessibility), steuern (tap/text/swipe/key/app_launch, nur entsperrt), ausgeben (Overlay ueber dem laufenden Bild + ARIAs **echte** Stimme per `tts_request`, weil Fire TV Sticks oft keine deutsche TTS-Engine haben), Audio-Fokus (Film wird leiser/angehalten), Sprachdialog mit demselben STT-Protokoll wie die App. Fester Signaturschluessel, damit Builds als Update statt als Paket-Konflikt ankommen +- [x] **Ausrollen per Satellit** (ADB over Network): APK installieren, Berechtigungen per `appops`/`pm grant` erteilen und die **RVS-Zugangsdaten per Intent provisionieren** — am Fire TV tippt man nichts ein, QR-Scannen geht dort nicht. Geraetename am PC vergeben, vorhandener Name wird vorgeschlagen +- [x] **Agent-Historie** in der Diagnostic: Befehle + Screenshots pro Agent, gruppiert pro User-Nachricht, aufklappbar +- [x] **Jellyfin-Integration**: mehrere Server mit API-Key, ARIA steuert die Wiedergabe ueber die API statt sich durch die Oberflaeche zu klicken; eingeschlafene Sitzungen baut sie selbst neu auf +- [x] **Auslastungs-Monitor** pro Compute-Box: live `nvidia-smi` + Verlaufs-Graphen (GPU + Tokens) ueber RVS, Historie liegt auf der Box +- [x] **OpenAI-Endpunkt fuers lokale LLM** (+ optionales `openhands`-Profil); `.env` gewinnt immer, Diagnostic-Felder dann nur lesend +- [x] **Teilen-Ziel in der App** + **Sprachnachricht zu Anhaengen** + **Zwischenruf per Sprache** +- [x] **Trigger mit Projekt-Kontext**: die Antwort kommt dort zurueck, wo der Timer gestellt wurde (vorher immer Hauptchat), und `trigger_list` unterscheidet „schon gefeuert" von „deaktiviert" + +#### Jagd auf verlorene Sprachnachrichten (die lange Kette) + +Ein hartnaeckiges „die erste Sprachnachricht kommt nicht durch" waren am Ende +**fuenf unabhaengige Ursachen** — hier dokumentiert, weil jede einzelne fuer +sich plausibel aussah: + +- [x] **200-MB-Broadcast** — der RVS ist ein Broadcast-Relay: ein per + `file_request` nachgeladenes 150-MB-Video ging als ~200 MB base64 an **alle** + Clients. Die STT/TTS-Worker starben daran mit Code 1009 und nahmen die + laufende Aufnahme mit; die App starb am OOM und wurde von Android neu + gestartet → Auto-Re-Download → von vorn (Schleife alle ~70s). Fix dreifach: + Worker-`max_size` an den RVS angeglichen, **Datei-Antworten gehen nur noch an + den Fragenden** (requestId-Korrelation im RVS), und die App holt ueber 25 MB + nichts mehr ungefragt +- [x] **`spawn E2BIG`** im Proxy — der System-Prompt lief als Kommandozeilen- + Argument gegen `ARG_MAX` (131072). Jetzt `--system-prompt-file` +- [x] **RVS-Allow-List** verwarf fuenf Nachrichtentypen still (`stt_lease*`, + `chat_ack`, `stt_transcribe_*`) — jede Aufnahme startete verspaetet, erste + Silben weg +- [x] **Whisper-Kaltstart** — Session wurde angelegt, bevor das Modell geladen + war; Audio lief ins Leere +- [x] **Zombie-Verbindung** in der App — zeigte „getrennt", empfing aber weiter; + die Aufnahme-Sperre fragt jetzt den Socket statt den gemerkten Zustand +- [x] **Lange Sprachnachrichten brachen mitten im Satz ab** — der Endpointer + zaehlte seine **eigene** Rechenzeit als Stille: der 200ms-Tick wartete auf die + Zwischen-Transkription, und die lief jedes Mal ueber den kompletten Buffer + (bei zwei Minuten mehrere Sekunden). Jetzt laeuft sie nebenher und sieht nur + die letzten 30s; der finale Text kommt unveraendert aus dem ganzen Buffer + ### Phase 2 — ARIA wird produktiv - [ ] Erste Skills bauen lassen (yt-dlp, pdf-extract, etc. — durch normale Anfragen)