diff --git a/README.md b/README.md index ed34f70..00ef96c 100644 --- a/README.md +++ b/README.md @@ -464,6 +464,44 @@ manueller Diagnostic-Klick) gehoeren seed_rules zum Brain-Code und werden mit jedem Deploy ausgerollt. Editieren = `SEED_RULES`-Liste anpassen, Brain neu starten. +### Beispiel: `flugwetter` + +Zeigt gut, wie ein Skill mit Zugangsdaten und mehreren Quellen aussieht — +Briefing fuer **EDWI** (Wilhelmshaven-Mariensiel, Piste 02/20), nur mit +Python-Bordmitteln, keine pip-Pakete. + +| Was | Woher | Kosten | +|---|---|---| +| METAR/TAF | aviationweather.gov | frei | +| Wind, Boeen | Open-Meteo **ICON-D2** | frei | +| Bedeckung, Sicht | DWD **MOSMIX** Station 10125 | frei | +| GAFOR, Karten | **ftp.pcmet.de** | Stefans pc_met-Konto | + +Die pc_met-Zugangsdaten stehen in der **Skill-Konfiguration** +(`pcmet_user` / `pcmet_password`), nie im Chat. `ftp.pcmet.de` ist die vom DWD +dokumentierte Kundenschnittstelle — kein Nachbauen des Browser-Logins noetig. +`action=discover` listet, was auf dem Server liegt; `action=fetch` holt eine +Karte nach `/shared/uploads` und gibt sie als `[FILE:]`-Marker zurueck, sodass +ARIA sie anzeigen oder an einen Agenten schicken kann. + +Zwei Dinge, die den Unterschied machen: + +- **Seitenwind statt nur Wind.** Gerechnet gegen Piste 02/20 und gegen Stefans + 15-kt-Grenze (`crosswind_limit_kt`), bewertet werden die **Boeen**. +- **Jede Zahl nennt ihre Herkunft.** Die Wolkenuntergrenze ist entweder + *gemessen* (METAR), ein ausdruecklich markierter *Schaetzwert* + (Temp/Taupunkt, 400-ft-Regel) oder *nicht verfuegbar* — dann steht da, dass + man ins GAFOR schauen muss. `CAVOK` wird als eigene Aussage behandelt und + unterdrueckt die Schaetzung, die sonst direkt widersprechen wuerde. + Genau daran war ein Briefing vorher gescheitert: METAR meldete `NCD` + (AUTO-Station), das Bodenmodell meldete bedeckt, und niemand wusste, was gilt. + +Oben im Ergebnis steht eine **KURZFASSUNG in ganzen Saetzen zum Vorlesen** +(„fuenftausend Fuss", nicht „5000 ft") — eine vorgelesene Tabelle versteht +niemand. Fuer die Ausgabe auf einem Geraet kombiniert ARIA: +`run_flugwetter` → optional `action=fetch` → `host_notify(text=, +image_path=, mode='both', seconds=0)`. + --- ## Diagnostic — Selbstcheck-UI und Einstellungen @@ -473,7 +511,7 @@ Erreichbar unter `http://:3001`. Teilt das Netzwerk mit der Bridge. ### Tabs - **Main**: Brain/RVS/Proxy-Status, Chat-Test, "ARIA denkt..."-Indikator, **💭 Gedanken-Stream** (zentrales Modal, zeigt live alle Tool-Calls + Phasen mit Zeitstempel und Trennlinien bei langen Pausen), End-to-End-Trace, Container-Logs -- **Gehirn**: Memory-Browser (Vector-DB), Suche mit zwei Modi (**📝 Wortlich** = Substring-Match Default + **🧠 Semantisch** mit Score-Threshold), **Advanced Search** (aufklappbares Panel, beliebig viele AND/OR-verknuepfte Felder, + Button fuer mehr Zeilen), Type+Pinned-Filter (greifen auch in der Suche), klappbare Type-Kategorien (Default eingeklappt), Add/Edit/Delete mit Category-Autosuggest, **📎 Anhaenge** pro Memory (Bilder/PDFs/...): Upload + Thumbnail-Vorschau + Lightbox + Lösch-Button, 📎N-Badge in der Liste, automatischer Cleanup beim Memory-Delete. ℹ-Info-Modal das erklaert welche Types FEST in den Prompt vs. Cold Memory wandern. **📄 Druckansicht** (Strg+P → PDF). Konversation-Status mit Destillat-Trigger, **Token/Call-Metrics mit Subscription-Quota-Tracking**, Bootstrap & Migration (3 Wiederherstellungs-Wege), Gehirn-Export/Import (tar.gz) +- **Gehirn**: Memory-Browser (Vector-DB), Suche mit zwei Modi (**📝 Wortlich** = Substring-Match Default + **🧠 Semantisch** mit Score-Threshold), **Advanced Search** (aufklappbares Panel, beliebig viele AND/OR-verknuepfte Felder, + Button fuer mehr Zeilen), Type+Pinned-Filter (greifen auch in der Suche), klappbare Type-Kategorien (Default eingeklappt), Add/Edit/Delete mit Category-Autosuggest, **📎 Anhaenge** pro Memory (Bilder/PDFs/...): Upload + Thumbnail-Vorschau + Lightbox + Lösch-Button, 📎N-Badge in der Liste, automatischer Cleanup beim Memory-Delete. ℹ-Info-Modal das erklaert welche Types FEST in den Prompt vs. Cold Memory wandern. **📄 Druckansicht** (Strg+P → PDF). **Datum/Uhrzeit pro Gedanke** („angelegt 03.10.26, 09:14 · geändert … (vor 3 Std)") — `created_at`/`updated_at` lagen immer schon in der DB und wurden nur nie angezeigt. Dazu **Sortierung** (nach Typ gruppiert oder Anlage/Aenderung auf-/absteigend; bei Zeit-Sortierung flach statt gruppiert) und ein **🕒 Zeitraum-Filter** (von/bis, umschaltbar angelegt/geaendert, Schnellwahl Heute / 7 / 30 Tage) der auch fuer Such-Treffer gilt. Konversation-Status mit Destillat-Trigger, **Token/Call-Metrics mit Subscription-Quota-Tracking**, Bootstrap & Migration (3 Wiederherstellungs-Wege), Gehirn-Export/Import (tar.gz) - **Skills**: Liste aller Skills mit Logs pro Run, Activate/Deactivate, Export/Import als tar.gz, "von ARIA"-Badge fuer selbst gebaute - **Trigger**: passive Aufweck-Quellen. **Timer** (einmalig, ISO-Timestamp oder via `in_seconds` als Server-Berechnung) + **Watcher** (recurring, mit Condition + Throttle). Liste aktiver Trigger + Logs pro Feuer-Event. Modal mit Type-Dropdown, Live-Anzeige aller verfuegbaren Condition-Variablen (`disk_free_gb`, `hour_of_day`, `current_lat/lon`, `last_user_message_ago_sec`, …). **Drei GPS-Funktionen** mit unterschiedlicher Semantik: - `near(lat, lon, r)` — SOLANGE im Radius (mit Throttle gegen Spam). Use-Case: „bin ich noch in der Nähe von X?" @@ -505,7 +543,11 @@ Erreichbar unter `http://:3001`. Teilt das Netzwerk mit der Bridge. - **Debug-API ohne SSH** (Diagnostic-Server, Port 3001): - `GET /api/chat-backup?lines=N` — letzte N Zeilen aus `chat_backup.jsonl` (Default 200, max 5000) als geparstes JSON. Hilfreich um nachzuvollziehen was ARIA tatsaechlich gemacht hat. - `GET /api/agent-stream?lines=N` — gleiche Mechanik fuer den persistierten Live-Stream (Tool-Calls + Inputs + Outputs). -- **OAuth-Callback-Pipeline**: Caddy davor terminiert TLS via Let's Encrypt, RVS hat einen HTTP-Listener auf demselben Port wie der WebSocket. Provider (Spotify/Dropbox/Discord/...) redirecten den User an `https://{RVS_HOST}/oauth/callback/{service}` → RVS broadcastet als `oauth_callback`-WS-Message → aria-bridge forwarded an Brain → Brain matched `state`, tauscht `code` gegen Token, persistiert in `/shared/config/oauth_tokens.json`. Token-Refresh laeuft automatisch. ARIA hat vier Brain-Tools: **`oauth_register_provider`** (legt URLs eines neuen Providers wie Dropbox/Discord/Notion/... on-demand in `oauth_apps.json` an — Credentials bleiben Stefans Job), `oauth_authorize`, `oauth_get_token`, `oauth_revoke` +- **OAuth-Callback-Pipeline**: Caddy davor terminiert TLS via Let's Encrypt, RVS hat einen HTTP-Listener auf demselben Port wie der WebSocket. Provider (Spotify/Dropbox/Discord/...) redirecten den User an `https://{RVS_HOST}/oauth/callback/{service}` → RVS broadcastet als `oauth_callback`-WS-Message → aria-bridge forwarded an Brain → Brain matched `state`, tauscht `code` gegen Token, persistiert in `/shared/config/oauth_tokens.json`. Token-Refresh laeuft automatisch. ARIA hat fuenf Brain-Tools: **`oauth_register_provider`** (legt URLs eines neuen Providers wie Dropbox/Discord/Notion/... on-demand in `oauth_apps.json` an — Credentials bleiben Stefans Job), `oauth_authorize`, `oauth_get_token`, **`oauth_call`**, `oauth_revoke` +- **Sprachmodell**: die Auswahlliste kommt aus **Anthropics eigenem Modell-Katalog** (`downloads.claude.ai/model-catalog/v1/catalog.json`, Surface `cc`) — dieselbe Quelle, aus der sich Claude Code bedient. Oeffentlich, ohne API-Key. Oben die **Tier-Aliase** (opus/sonnet/haiku/fable), die automatisch der neuesten Version folgen; darunter die **exakten Versionen**, aeltere als solche markiert. „↻ Aktualisieren" holt frisch, sonst 6h-Cache mit Datei-Fallback fuer offline. **🔬 Testen** schickt eine echte Mini-Anfrage durch den ganzen Weg und zeigt, welches Modell tatsaechlich geantwortet hat (aus `modelUsage.canonicalModel` der CLI — das Modell selbst zu fragen waere unzuverlaessig). Vier Ergebnisse: Tier aufgeloest (gruen), exakte Version (gruen), **nicht erkannt** (gelb — der Proxy haette still `opus` eingesetzt), ungueltig (rot, mit CLI-Begruendung) +- **Datenschutz-Schalter**: die drei Kanaele, ueber die Claude Code zusaetzlich sendet (`DISABLE_ERROR_REPORTING`, `DISABLE_TELEMETRY`, `DISABLE_FEEDBACK_COMMAND`) pruefen und setzen. Geschrieben wird nach `~/.claude/settings.json` unter `env` — die CLI liest das bei jedem Aufruf, **kein Neustart noetig**. Geprueft wird, was wirklich im Prozess ankommt: eine per docker-compose gesetzte Variable gewinnt und wird als gesperrt angezeigt, statt einen wirkungslosen Haken anzubieten. **Nicht** dasselbe wie die Trainings-Einstellung — die steht im Anthropic-Konto (Link daneben) +- **Warnung bei veralteten Proxy-Patches**: der Proxy kopiert `proxy-patches/` beim **Start**. Wer nach einem `git pull` nur neu startet — oder neu startet, bevor der Pull durch ist — laeuft still mit der alten Fassung. Nichts deutet darauf hin. Die Einstellungen vergleichen jetzt die Zeitstempel und zeigen den fertigen Befehl (`--force-recreate proxy`) +- **Anhang-Limit** (System & Wartung): Groesse fuer Memory-Anhaenge, Default 64 MB. Liegt in `runtime.json`, das Brain liest es bei jedem Upload neu — greift sofort. Ueber 64 MB warnt die UI, weil die Handy-App darueber nichts mehr herunterlaedt --- @@ -1067,6 +1109,26 @@ nichts zu tun. Auf dem Fire TV gibt es keinen Touchscreen, dafuer das D-Pad. | 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`) | +| Bild + Text | `host_notify(image_path=/shared/uploads/...)` blendet ein Bild MIT Text ein — z.B. eine Wetterkarte | + +**Wie die Einblendung wieder weggeht.** Eine feste Anzeigedauer ist immer +geraten: mal zu kurz zum Lesen, mal steht sie laengst im Weg. Darum bedeutet +`seconds=0`: **bleibt, bis Stefan etwas tut.** + +- *Fernbedienung*: der Accessibility-Dienst bekommt `onKeyEvent` und raeumt die + Einblendung weg — gibt die Taste aber mit `return false` **weiter an den + Film**. Es geht kein Tastendruck verloren, der Player bleibt bedienbar. +- *Touch*: `FLAG_WATCH_OUTSIDE_TOUCH` meldet eine Beruehrung daneben; die geht + dank `FLAG_NOT_TOUCHABLE` gleichzeitig an die App darunter. +- *Notbremse*: nach 10 Minuten verschwindet sie in jedem Fall. + +> Bewusst **nicht** der naheliegende Weg (Overlay faengt Tasten selbst ab): +> dafuer muessten `FLAG_NOT_FOCUSABLE` und `FLAG_NOT_TOUCHABLE` weg — und dann +> nimmt die Einblendung dem laufenden Film JEDE Eingabe, solange sie steht. +> +> Der Accessibility-Dienst braucht dafuer `canRequestFilterKeyEvents`. Nach +> einem Update also pruefen, ob er in den Bedienungshilfen noch aktiv ist — +> Android schaltet Dienste bei geaenderter Konfiguration gern ab. > Fire TV Sticks haben oft **keine deutsche TTS-Engine**. Darum laeuft die > Sprachausgabe bewusst nicht ueber die Geraete-Stimme, sondern ueber ARIAs @@ -1147,6 +1209,40 @@ vorgeschlagen; nur wenn es keinen gibt, kommt der automatisch generierte. 6. **Panic Button**: `docker compose down` → sofort stoppen 7. **Alles loggen** — Stefan sieht immer was passiert +### Secrets und was bei Anthropic landet + +ARIA laeuft ueber Claude Code auf einem Claude-Abo. **Alles, was ARIA sieht — +auch jedes Tool-Ergebnis — wird uebertragen und gespeichert.** Bei Consumer- +Plaenen (Free/Pro/Max) haengt es an einer Einstellung im Konto, ob daraus auch +Trainingsdaten werden; die Aufbewahrung betraegt entsprechend 5 Jahre oder +30 Tage ([claude.ai/settings/data-privacy-controls](https://claude.ai/settings/data-privacy-controls), +Details in Anthropics [Data-usage-Doku](https://code.claude.com/docs/en/data-usage)). + +Daraus folgen drei Regeln: + +1. **Secrets nie in den Chat tippen.** Das ist der Weg, ueber den hier + tatsaechlich einmal ein `client_secret` abgeflossen ist — nicht ueber ein + Tool, sondern weil es eingetippt und von ARIA zurueckzitiert wurde. Der + System-Prompt und die seed_rules weisen ARIA inzwischen an, das abzulehnen + und ein Secret nie zu wiederholen. +2. **Zugangsdaten gehoeren in eine Konfiguration, nicht in Code oder Chat.** + OAuth → Diagnostic → OAuth-Apps. Alles andere (Benutzername/Passwort, + API-Keys) → **Skill-Konfiguration** (`skill_set_config`), kommt zur Laufzeit + als `CFG_` an und wird in der Oberflaeche maskiert. +3. **ARIA bekommt Zugangstokens nicht mehr zu sehen.** `oauth_get_token` sagt + nur noch, OB authentifiziert ist. Fuer API-Aufrufe gibt es **`oauth_call`**: + das Brain haengt die Authorization selbst an, fuehrt den Request aus und + gibt nur die Antwort zurueck — der Token verlaesst den Brain-Prozess nicht. + Abgesichert durch eine Host-Sperre: nur https und nur Hosts, die zum + Provider gehoeren (Vergleich auf den letzten zwei Labels, **nicht** per + `endswith` — sonst waere `boesespotify.com` durchgerutscht). + +> Was ARIA NICHT schuetzt: sie laeuft mit Root im Proxy-Container und hat +> `/shared` gemountet. Sie *kann* `/shared/config/*.json` lesen, wenn sie +> hinschaut — und was sie liest, ist Tool-Ergebnis. Die Dateirechte (600) +> helfen dagegen nicht. Behandle jedes dort erreichbare Secret als +> „sichtbar, sobald ARIA hinschaut". + --- ## Haeufige Befehle @@ -1330,6 +1426,11 @@ docker exec aria-brain curl localhost:8080/memory/stats - [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" +- [x] **Modell-Liste von Anthropic** statt handgepflegt — und feste Versionen greifen wirklich. Vorher schmolz `extractModel` jeden unbekannten Namen still auf `opus` ein: eine bewusst gewaehlte Version wurde ohne Meldung durch eine andere ersetzt. Dazu ein **Test-Knopf**, der zeigt, welches Modell tatsaechlich geantwortet hat — moeglich wurde das erst, nachdem `normalizeModelName` aufhoerte, den echten Namen zu ueberschreiben +- [x] **Datenschutz**: die drei Claude-Code-Sendekanaele in der Diagnostic pruef- und abschaltbar (ohne Neustart), **`oauth_call`** statt Token-Herausgabe, Secrets-Regeln in Prompt und seed_rules, Warnung bei veralteten Proxy-Patches +- [x] **Anhang-Limit einstellbar** (Default 20 → 64 MB, greift sofort) und **Zeitstempel/Sortierung/Zeitraum** bei den Gedanken +- [x] **Flugwetter-Skill** mit pc_met-Anbindung, Seitenwind gegen Pistenrichtung und Herkunftsangabe pro Zahl; Ausgabe als Einblendung + Sprache auf einem Agenten +- [x] **Einblendung geht per Tastendruck weg** statt nach geratener Zeit — ueber `onKeyEvent` des Accessibility-Dienstes, der die Taste an den Film weiterreicht #### Jagd auf verlorene Sprachnachrichten (die lange Kette)