feat: 2 neue seed_rules + Diagnostic-Persistenz fuer agent_stream + chat-backup API

Befund aus chat_backup.jsonl-Analyse heute: ARIA ist 3x auf oauth_authorize
gefallen statt oauth_get_token (Stefan musste manuell einloggen), und beim
PDF-Skill ist sie nach Stefans "Variante bitte" zu Ad-hoc-Bash-Befehlen
auf der VM gedriftet ("ich lass den Code direkt laufen") — Skill wurde
unbrauchbar. Beides genau die Antipattern die wir mit den seed_rules
abdecken wollten, nur waren die zu schwach formuliert.

seed_rules (jetzt 9 statt 7):
- oauth-reauth-reflex: bei 401 ZUERST oauth_get_token, NUR bei dessen
  Fehler oauth_authorize. Stefan zu Re-Login schicken ist das aergerlichste
  Antipattern (er sitzt im Auto, muss Handy rauskramen).
- no-skill-drift: kaputter Skill -> skill_logs + skill_update, NIEMALS
  zu Ad-hoc-Bash wechseln (Skill wird Karteileiche). Plus: "ich baue
  dir einen Skill" SAGEN ohne skill_create zu rufen ist verboten —
  Stefan checkt die Liste und verliert das Vertrauen.

agent_stream-Persistenz:
- diagnostic/server.js schreibt jeden agent_stream-Event parallel zum
  Broadcast in /shared/logs/agent_stream.jsonl (soft-cap 50 MB mit
  half-truncate beim Ueberlauf).
- Live-View laedt beim Page-Load + Sub-Tab-Switch die letzten 200
  Eintraege via /api/agent-stream. Browser-Reload / Standby verliert
  damit den Verlauf nicht mehr.

Debug-API ohne SSH:
- GET /api/chat-backup?lines=N (Default 200, Max 5000) — geparstes JSON
  der letzten N Zeilen aus chat_backup.jsonl
- GET /api/agent-stream?lines=N — gleiches fuer den persistierten Stream

README:
- Neuer Abschnitt "## Skills — Architektur" mit Skill-Layout,
  Drei-Stufen-Daten-Modell (OAuth / config_schema / Brain-Daten),
  Versionierung, Anti-Friedhof, seed_rules (alle 9 aufgelistet).
- Diagnostic-Sektion um agent_stream-Persistenz + neue Debug-Endpoints
  ergaenzt.
- Roadmap: Phase B "Skill-Architektur P0-P4" abgehakt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-29 23:06:56 +02:00
parent 5e1cb2d26a
commit aaaf118cb7
4 changed files with 261 additions and 1 deletions
+96 -1
View File
@@ -324,6 +324,92 @@ aria-brain → Antwort → Bridge → RVS → App
---
## Skills — Architektur
Skills sind ARIAs wiederverwendbare Faehigkeiten. Jeder Skill ist ein
Python-Programm in seinem eigenen `local-venv`. ARIA legt sie selbst via
`skill_create` an, fixt Bugs mit `skill_update`, rollt zur Not zurueck
mit `skill_rollback`.
### Skill-Layout
```
/data/skills/<name>/
skill.json # Manifest (Metadata + config_schema + version_history)
run.py # Entry-Point (Python via venv-python)
requirements.txt # pip-Pakete fuer die venv
README.md # Beschreibung
venv/ # automatisch erzeugt
logs/<ts>.json # Run-Logs (append-only)
versions/v_<ts>/ # archivierte Vorgaengerstaende (vor jedem update_skill)
```
### Drei-Stufen-Daten-Modell
Skills muessen **niemals** Credentials hardcoden. Drei saubere Wege:
1. **OAuth2-Tokens** (Spotify, Google, GitHub, Reddit, …): Brain haelt
Client-Credentials und macht den Auth-Flow. Skill ruft
`GET {BRAIN_INTERNAL_URL}/oauth/<service>/token` und bekommt einen
frischen access_token (Auto-Refresh < 60 s Restzeit).
2. **Statische Werte** (API-Keys, User-IDs, Default-Geraete): Skill
deklariert ein `config_schema` in `skill.json`, Stefan setzt die
Werte in Diagnostic / App, Skill bekommt sie zur Laufzeit als
`CFG_<UPPER_NAME>` ENV.
3. **Brain-Daten** (Memories, Skills-Liste, Standort etc.): jeder Skill
kann gegen `BRAIN_INTERNAL_URL` Endpoints wie `/memory/search`,
`/memory/pinned`, `/skills/list` rufen — z.B. ein Wetter-Skill kann
Stefans Standort aus Memories holen statt ihn als Arg zu erwarten.
### Versionierung mit Rollback
`update_skill` archiviert den aktuellen Stand vor jeder strukturellen
Aenderung (entry_code, readme, pip_packages, config_schema, args) nach
`versions/v_<ts>/`. ARIA-Tools `skill_list_versions` + `skill_rollback`
(+ HTTP `/skills/{name}/versions` + `/rollback`) erlauben Wiederherstellung.
Vor jedem Rollback wird der aktuelle Stand als „safety-snapshot" gesichert
— der Rollback selbst ist also nicht destruktiv.
UI sowohl in Diagnostic (Skill-Detail → 📦 Versionen) als auch in der App
(SkillBrowser → Detail-Modal).
### Anti-Skill-Friedhof
ARIA hat frueher gerne 9 Spotify-Skills mit Suffixen `-v2`, `-aria`,
`-ctl`, `-fixed` gebaut statt einen sauberen zu pflegen.
`skills.create_skill()` rejected jetzt hart:
- Versions-Suffixe (`-v\d+`, `_v\d+`, `-new`, `-fixed`, `-old`,
`-alt`, `-copy`, `-final`, `-clean`)
- Prefix-Kollisionen (`spotify` existiert → `spotify-aria` rejected)
Plus die Skill-Regeln (siehe naechster Abschnitt) erinnern ARIA bei jedem
Chat-Turn an die richtigen Patterns.
### Skill-Regeln (seed_rules)
`aria-brain/seed_rules.py` enthaelt 9 `type=rule, pinned=true,
source=seed`-Memories, die bei jedem Brain-Start idempotent in die
Vector-DB geschrieben werden (`migration_key`-basiert). Sie tauchen in
jedem Chat-Turn im Hot-Memory-Block auf:
- **list-before-create** — IMMER `skill_list` vor `skill_create`
- **no-version-suffix** — keine `-v2`/`_v3`-Namen, Versionsverwaltung ist intern
- **update-not-recreate** — defekten Skill mit `skill_update` fixen, nicht neu bauen
- **no-hardcoded-credentials** — OAuth-Tokens via `oauth_get_token`, keine client_secrets im Code
- **config-schema-for-settings** — statische Werte via `config_schema`, nicht hardcoded
- **brain-internal-url** — `BRAIN_INTERNAL_URL` Endpoints inkl. `/oauth/<s>/token`, `/memory/search`, `/memory/pinned`, `/skills/list`
- **oauth-reauth-reflex** — bei 401: ZUERST `oauth_get_token` (Auto-Refresh), nur bei dessen Fehler `oauth_authorize`
- **no-skill-drift** — kein Drift vom Skill zu Ad-hoc-Bash-Befehlen. Skill kaputt? `skill_logs` + `skill_update`. Niemals nur SAGEN „ich baue dir einen Skill", wenn `skill_create` nicht wirklich gefeuert wird
- **external-api-auth-strategy** — OAuth2 → `oauth_get_token`, sonst `config_schema`, NIEMALS hardcoden
Im Gegensatz zu `aria-data/brain-import/` (User-Saatgut, gitignored,
manueller Diagnostic-Klick) gehoeren seed_rules zum Brain-Code und werden
mit jedem Deploy ausgerollt. Editieren = `SEED_RULES`-Liste anpassen,
Brain neu starten.
---
## Diagnostic — Selbstcheck-UI und Einstellungen
Erreichbar unter `http://<VM-IP>:3001`. Teilt das Netzwerk mit der Bridge.
@@ -352,7 +438,10 @@ Erreichbar unter `http://<VM-IP>:3001`. Teilt das Netzwerk mit der Bridge.
- **Voice Export/Import**: einzelne Stimmen als `.tar.gz` zwischen Gameboxen mitnehmen
- **Settings Export/Import**: `voice_config.json` + `highlight_triggers.json` als JSON-Bundle
- **Claude Login**: Browser-Terminal zum Einloggen in den Proxy
- **ARIA Live**: read-only Mirror der Claude-Code-Session — alle Tool-Calls + Inputs + Outputs live in einer Monospace-Liste, farbcodiert. Plus ⛔ **Not-Aus**-Button der per RVS einen `cancel_request` mit `hard:true` ausloest → aria-bridge ruft den proxy-internen `/cancel-all` Side-Channel → alle Claude-Subprocesses werden sofort gekillt
- **ARIA Live**: read-only Mirror der Claude-Code-Session — alle Tool-Calls + Inputs + Outputs live in einer Monospace-Liste, farbcodiert. **Persistenz**: jeder `agent_stream`-Event wird parallel in `/shared/logs/agent_stream.jsonl` (soft-cap 50 MB) geschrieben, Live-View laedt beim Tab-Oeffnen / Page-Reload die letzten 200 Eintraege — Browser-Standby wirft nichts mehr weg. Plus ⛔ **Not-Aus**-Button der per RVS einen `cancel_request` mit `hard:true` ausloest → aria-bridge ruft den proxy-internen `/cancel-all` Side-Channel → alle Claude-Subprocesses werden sofort gekillt
- **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`
---
@@ -929,6 +1018,12 @@ docker exec aria-brain curl localhost:8080/memory/stats
- [x] **ARIA Live (Diagnostic) + Not-Aus**: read-only Mirror der Claude-Code-Session ersetzt den SSH-Tab. Tool-Calls + Inputs + Outputs (truncated 4 KB) live, farbcodiert. Roter ⛔ Not-Aus-Button schickt `cancel_request` mit `hard:true` → Bridge ruft den proxy-internen `/cancel-all` Side-Channel (Port 3457) → alle Claude-Subprocesses sofort tot. Plus: Idle-Watchdog im Proxy (20 min Inaktivitaet → Subprocess-Kill) + httpx-Timeout-Split im Brain (connect 10s / read 24h) damit lange Pentests durchlaufen
- [x] **OAuth2-Pipeline ueber RVS-Callback**: Caddy mit Let's Encrypt vor dem RVS, HTTP-Route `/oauth/callback/{service}` broadcastet als `oauth_callback`-WS-Message, aria-bridge forwarded an Brain, Token landet in `/shared/config/oauth_tokens.json` (mode 0600). ARIAs `oauth_register_provider`-Tool legt neue Provider on-demand an (URLs/scopes, nicht Credentials). Diagnostic + App haben beide Provider-Verwaltung inklusive Custom-Provider-Anlage
- [x] **Skill-Mgmt-Tools fuer ARIA**: `skill_update` (Code/README/pip_packages mit venv-Rebuild) + `skill_delete` — verhindert Skill-Friedhof mit `-v2`/`-fixed`-Suffixen. Plus App-seitiger SkillBrowser (Run + Live-Output + Logs der letzten 20 Runs) in Settings → 🛠️ Skills
- [x] **Skill-Architektur P0-P4**:
- `seed_rules` (9 pinned rule-Memories) werden bei jedem Brain-Boot idempotent in die DB geschrieben (`source=seed`, `migration_key`-basiert). Decken Skill-Friedhof, OAuth-Auth-Strategie, no-skill-drift, BRAIN_INTERNAL_URL ab
- Anti-Friedhof-Check in `create_skill`: rejected Versions-Suffixe + Prefix-Kollisionen hart
- Neuer Brain-HTTP-Endpoint `/oauth/<service>/token` + `BRAIN_INTERNAL_URL` ENV-Var fuer Skills — Skill ruft Brain fuer frischen Token statt client_secret hardzucoden
- `config_schema` in skill.json + zentrales `/shared/config/skill_configs.json` + `CFG_<NAME>` ENV beim Run + `skill_set_config` Brain-Tool + UI in Diagnostic & App (TextInput / Switch / password-Felder mit `***SET***`-Masking)
- Versionierung: jeder `skill_update` archiviert vorherigen Stand nach `versions/v_<ts>/` (ohne venv/logs). `skill_list_versions` + `skill_rollback` Brain-Tools (mit Safety-Snapshot + auto venv-Rebuild). UI mit Rollback-Button in Diagnostic & App
- [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)