Neues Feld scope=system|personal auf jedem Memory-Punkt. Bootstrap-Export
getrennt: System-Regeln (generisch, teilbar) vs. Persönliches (Name,
Zugangsdaten, Projekte). Import ist scope-sicher — ein System-Import löscht
NICHT die persönlichen pinned Memories. seed_rules + AGENT.md/TOOLING.md →
system, USER.md-Präferenzen → personal. Backfill für Bestand (57 system /
617 personal). Diagnostic: zwei Export-Buttons, scope-Badge (SYS/PRIV) +
Umschalter pro Memory.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stefans Repro "nichts geht mehr" kam NICHT von den Marker/Guard-Aenderungen,
sondern von der Speaker-ID: die Bridge-Logs zeigten fast durchgehend
"stt_endpoint mit leerem Text — ignoriert (reason=speaker_mismatch)" — ein aus
einem kaputten Enroll (AAC-als-PCM) entstandener Muell-Fingerprint hat Stefans
EIGENE Stimme abgelehnt und damit die komplette STT lahmgelegt.
Fix: Speaker-ID-Gating ist jetzt ein expliziter Schalter, Default AUS. Bei aus
laeuft die Pruefung GAR NICHT (fail-open, alle Stimmen durch) — ein schlechter
Enroll kann nie wieder alles abwuergen. Damit ist Stefans Problem schon durch den
Voxtral-Rebuild geloest (kein Loeschen noetig, der Check greift einfach nicht).
- voxtral + whisper bridge: SPEAKER_ID_ENABLED (Default False, ENV VOICE_ID_ENABLED),
_check_speaker faellt bei aus sofort fail-open zurueck; config-Broadcast
voiceIdEnabled setzt es zur Laufzeit.
- diagnostic: Schalter "Nur meine Stimme" in der Voice-ID-Sektion (Default aus,
Hinweis: erst an wenn enrollt), broadcastet + persistiert voiceIdEnabled.
Reihenfolge lt. Stefan: erst Konversation sauber, dann Multi-Person/nur-ich.
Deploy: docker compose up -d --build voxtral-bridge; aria-diagnostic neu starten.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ursache gefunden (WS-Direkttest beweist: Server-Pfad + Docker-Prune-API
funktionieren, aber der Klick kam nie an): runDiskCleanup() rief confirm()
VOR dem send(). Hatte der Browser Dialoge unterdrueckt ('Verhindern, dass
diese Seite weitere Dialoge erstellt' — bei dem vielen alert()/confirm()
im Diagnostic leicht passiert), gab confirm() automatisch false zurueck →
return vor send() → Button tat sichtbar nichts.
Fix: 'safe' laeuft OHNE confirm (Build-Cache + ungenutzte Images sind
ungefaehrlich, keine Volumes/Daten). Nur 'aggressive' (Volumes!) fragt
noch. Ergebnis wird am Button + Banner gezeigt, nicht nur per alert()
(das koennte genauso unterdrueckt sein).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ursache: Bridge-/chat-Aufruf hatte 1200s (20min) Timeout, der Proxy aber
24h. Lange Software-Dev-Turns dauern >20min → Bridge gab auf ('/chat
fehlgeschlagen: timed out'), der Brain lieferte die Antwort Minuten spaeter
(nur im Log, keine Bubble), und der Diagnostic-Kontext blieb auf 'running'
haengen (Folgenachrichten in die Queue trotz idler ARIA; nur Ctrl+R half,
verlor aber die Queue-Nachricht).
- Bridge: /chat-Timeout 1200s → 24h (env BRAIN_CHAT_TIMEOUT_SEC), passend
zum Proxy.
- Diagnostic: reconcileDiagStates() gleicht lokalen 'running'-Zustand gegen
die Brain-queue-status ab (2 Polls Karenz). Haengt ein Kontext, obwohl der
Brain nicht busy ist → Queue weiterschalten: angestellte Nachricht geht
automatisch raus statt verloren.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Button rief copyDiskCmd() → kopierte nur den docker-Befehl in die
Zwischenablage (ueber http scheitert navigator.clipboard oft still →
'keine Funktion'). Jetzt fuehrt runDiskCleanup() das Aufraeumen echt aus:
Server-seitig ueber die Docker-Daemon-API (Socket ist gemountet) —
/build/prune?all=true + /images/prune (dangling=false), ohne Volumes =
keine Daten weg. 'Aggressiv' (zusaetzlich Container+Volumes) als eigener
'Jetzt ausfuehren'-Button mit Warnung. Rueckmeldung: wieviel frei wurde;
Banner aktualisiert sich per periodischem disk_status.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neben Senden ein 'Zwischenruf' (App: oranger Button, nur wenn ARIA im
aktiven Kontext arbeitet; Diagnostic: Buttons neben beiden Senden). Geht
NICHT in die Queue und bricht NICHT ab — die Nachricht wird in den
laufenden claude-Subprozess geschoben; er greift sie an der naechsten
Tool-Grenze auf.
Technik:
- proxy-patches/manager.js: claude laeuft jetzt im --input-format
stream-json-Modus, initialer Prompt als stream-json User-Message,
stdin bleibt OFFEN; sendMessage() schiebt weitere User-Messages nach;
bei 'result' wird stdin geschlossen (Turn endet sauber). Ersetzt die
bisherigen sed-Patches (jetzt volle Datei via cp, docker-compose.yml).
- proxy-patches/routes.js: Side-Channel POST /interject {projectId,text}
→ subprocess.sendMessage der Kontext-Subprozesse.
- rvs: 'interject' erlaubt. bridge: RVS interject → Proxy /interject.
- App/Diagnostic: Zwischenruf-Buttons + lokale '📣 Zwischenruf'-Bubble.
Empirisch verifiziert: mid-turn injizierte Message wird an der naechsten
Tool-Grenze aufgegriffen (nicht mitten in einem blockierenden Befehl).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der cancel_request-Handler rief openclaw doctor --fix auf dem Container
aria-core auf, den es im aktuellen Stack nicht mehr gibt → der laufende
claude-Subprozess wurde nie gekillt, ARIA lief weiter. Jetzt sendet er
RVS cancel_request{hard:true} → Bridge → Proxy /cancel-all killt den Run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Brain: /projects/status + /list liefern has_files + file_count pro Projekt
(Scan /shared/projects/<id>/). Ersetzt das manuelle Code-Flag als primaeren
Indikator. VM-Liste liefert boot_cmd (lesbarer aria-vm-Startbefehl).
- App: 📄-Symbol (+ Anzahl) an Projekten mit Dateien im ProjectsBrowser.
DesktopTile zeigt pro VM den Start-Befehl als Wert dahinter.
- Diagnostic: 📄-Symbol (+ Anzahl, Tooltip) an Projekten mit Dateien.
Hinweis (kein Code): der VNC-Stream laeuft komplett durch RVS — der Port ist nur
der interne QEMU-Display-Port, den die Bridge lokal auf dem Host nutzt; die App
oeffnet nie einen Port (firewall-unabhaengig).
py/tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Editor zeigte "keine Datei", obwohl ARIA schon Dateien geschrieben hatte — er las
NUR den Live-code_file-Stream, nie den Bestand. Jetzt:
- Brain: GET /projects/<id>/files + /file (liest /shared/projects/<id>/, pfad-sicher,
512KB-Cap). kind in ProjectUpdateBody (PATCH akzeptiert 'code'|'chat').
- App: brainApi.listProjectFiles/readProjectFile/setProjectKind. CodeEditorTile
holt beim Oeffnen die vorhandene Dateiliste + laedt Inhalt (Live-Version hat
Vorrang). ProjectsBrowser-Edit: Code-Projekt-Toggle (spiegelt sofort in
projectFocus → Cockpit-Panels).
- Diagnostic: </> Code-Toggle je Projektzeile + Code-Badge.
py/node/tsc clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Symptom: Satellit fand nur Docker-Container (192.168.65.x / 172.18.x) statt der
echten LAN-Geraete. Ursache ist kein Bug, sondern das Deployment-Netz: auf Docker
Desktop (Mac/Windows) ist network_mode:host das Docker-VM-NAT, nicht das echte LAN
— mDNS/SSDP erreichen die realen Geraete nicht.
- satellite.py: _net_context() ermittelt primary_ip + alle IPs und WARNT, wenn der
Satellit in einem Docker-/NAT-Netz laeuft (192.168.65.x oder 172.16-31.x). Netz-
Info wird in sat_hello + sat_devices mitgeschickt und beim Start geloggt.
- Diagnostic: zeigt Netz (primary_ip) pro Satellit + eine rote ⚠-Box mit der
Warnung, wenn er im falschen Netz sitzt.
- README/compose: klar dokumentiert, dass der Satellit im ECHTEN Ziel-LAN laufen
muss (Linux Docker Engine ODER nativ python satellite.py); Docker-Desktop-Falle.
py/node clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Das Diagnostic haengt selbst am RVS-Raum und kennt die sat_*-Broadcasts jetzt:
- server.js: Satelliten-Registry (sat_hello), leitet sat_devices an den Browser,
gibt die Liste beim init mit; Browser-Aktionen sat_list + sat_discover.
- index.html: neuer Haupt-Tab "Satelliten" — Karten pro Satellit (online/offline,
Standort, Capabilities, read-only/steuerbar) mit "Geraete scannen" → Live-Liste
der erkannten Geraete (Typ/IP/Modell/DIAL/MAC).
Kein Brain/Bridge-Rebuild fuer diesen Teil noetig (nur diagnostic). node -c OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diagnostic bekommt denselben Queue-Automaten wie die App: anstellen statt
abbrechen, awaiting_reply pausiert die Queue (naechste Eingabe beantwortet die
Rueckfrage), Queue-Banner mit loeschbaren Eintraegen ueber dem Eingabefeld,
und Pro-Kontext-Textfeld-Entwuerfe (Feldinhalt bleibt beim Kontextwechsel
erhalten). rvs_chat-Handler liest awaiting_reply aus der Bridge-Payload.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Das Auge/Toggle war faelschlich nur in der vertikalen Projektliste unter
Einstellungen — Stefan managed Projekte aber ueber die Ordner-Bubbles im
Kontext-Streifen auf dem Main-Tab, und der filterte hidden gar nicht
(verstecktes Projekt blieb sichtbar, kein Auge).
renderContextStrip: versteckte Projekte standardmaessig raus, 🙈/👁-Auge pro
Bubble (eigenes onclick + stopPropagation, wechselt nicht den Kontext),
"versteckte anzeigen (N)"-Toggle-Chip am Ende; setStripProjectHidden patcht
+ raeumt Focus wenn noetig. project_changed refresht jetzt Streifen UND Liste.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die /-Response hatte keinen Cache-Control-Header. Der Browser cachte das
grosse Single-HTML-Dashboard heuristisch und servierte trotz (soft) Reload
die alte Inline-JS/CSS — neue Features (Projekte-verstecken-Button, Auge,
Token-Ersparnis-Card) tauchten erst nach Hard-Reload auf. Jetzt no-store +
no-cache, so dass jeder Load die frische Version bekommt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Kern-Bug: der Diagnostic-Server reichte ein von RVS empfangenes
project_changed NIE an die Browser weiter — der Handler in index.html war
toter Code, der Diagnostic aktualisierte die Projektliste also nie live.
- server.js: RVS-Handler forwardet project_changed jetzt an die Browser-Tabs;
der /api/brain-Proxy broadcastet project_changed (RVS + lokal) nach jeder
erfolgreichen Projekt-Mutation (create/switch/end/archive/PATCH inkl. hidden).
- App ProjectsBrowser: sendet project_changed nach dem Verstecken/Sichtbar-
machen und laedt bei eingehendem project_changed selbst neu.
Damit: verstecken in der App -> sofort im Diagnostic weg (und umgekehrt),
ohne Seiten-Refresh. Diagnostic-Hide funktionierte schon (Daten/Proxy/Logik
korrekt) — versteckte sind per "Versteckte anzeigen (N)"-Toggle sichtbar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neues hidden-Flag pro Projekt (default false, bleibt voll nutzbar — nur
optisch aus der Liste ausgeblendet, unabhaengig von status/archived).
- projects.py: hidden in create_project + update_project-Patchkeys.
- main.py: ProjectUpdateBody.hidden → PATCH /projects/{id} setzt es.
- Diagnostic: pro Projekt-Bubble ein Auge (🙈 verstecken / 👁 sichtbar
machen); Header-Toggle "Versteckte anzeigen (N)" blendet sie temporaer
ein (gedimmt + Badge) zum Ansehen/Auswaehlen, ohne sie permanent
sichtbar zu machen. Auge im eingeblendeten Zustand macht sie dauerhaft
wieder sichtbar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adapter meldet bei Modellwechsel/Erst-Load service_status (service=llm):
loading -> ready (mit loadSeconds; freshlyDownloaded 🎉 bei langem Erst-Load)
oder error. Laeuft ueber den vorhandenen Pfad: Adapter -> RVS -> Diagnostic
(RVS-Client) -> Browser -> updateServiceStatus (generisch; nur Label 'Lokales
LLM' ergaenzt). Kein Bridge-/server.js-Change noetig.
Download-% gibt llama-swap nicht her — daher Zustands-Status (laedt/bereit/
Fehler), im gemeinsamen Service-Banner wie whisper/flux.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mehrere lokale Modelle, on-demand geladen/geswappt, in Diagnostic waehlbar.
Design: das Brain schickt den Modellnamen (aus local_llm.json) im llm_request
mit -> Adapter -> llama-swap laedt/swappt. Keine separate Gamebox-Config noetig.
- xtts: `llama`-Container -> `llama-swap` (unified-cuda), config.yaml mit
qwen3-8b (Standard) + qwen3-4b; Auto-Download via -hf, Cache /models geteilt
(qwen3-8b schon da). Adapter -> llama-swap:8080, Timeout 600s (Erst-Download).
- adapter: `model` aus dem Request an llama-swap durchreichen (Fallback env).
- brain: router.load_config liest localLlmModel; local_llm_chat(model=...);
agent gibt cfg-Modell mit; bridge reicht model durch (_local_llm + Route).
- diagnostic: /api/local-models-list (aus /shared/config/local_models.json,
seeded), local-llm-config um localLlmModel erweitert; Dropdown "Lokales
Modell" im Settings-Block + Erst-Download-Hinweis.
BLIND gebaut (Gamebox nicht testbar hier): llama-swap CLI/Config-Pfad beim
ersten Start via `docker logs aria-llama-swap` pruefen. Live-Lade-Status
(Adapter->Diagnostic) ist B0.5-2 (Folgeschritt).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zeigt pro Antwort, welcher Backend sie erzeugt hat — farbcodiert (lokal=gruen,
Claude=blau, Fast-Path=lila). Nur in Diagnostic (App bleibt Mama-tauglich).
- agent.chat() gibt jetzt (reply, answered_by) zurueck; an jedem Return-Punkt
gesetzt (fast-path/local/claude). Beide Aufrufer (main.py, background.py)
angepasst. main.py: ChatOut.answered_by.
- bridge: liest answered_by aus /chat, reicht es an _process_core_response,
broadcastet es im chat-Payload UND persistiert es in chat_backup (answeredBy)
→ bleibt nach Reload.
- diagnostic: srcBadgeHtml() rendert den Badge in Live-Chat + History;
server.js liefert answeredBy in der chat_history.
Erweiterbar: spaeter kann ein Bild-Backend (FLUX/Modellname) denselben Kanal
nutzen. Modellwechsel-fuer-Antworten (groessere Modelle bei mehr GPUs) bleibt
B0.5/Skalierungs-Thema im Plan.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pro Schalter ein kurzer Hilfetext (AN/AUS-Bedeutung, Testmodus-Warnung),
deutlichere Labels, Status-Zeile mit Ampel (⚪/🟡/🟢) + Hinweis auf aktuellen
B1a-Stand (lokal plaudert nur, Tools folgen in B1b).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
handleModels liest die kuratierte Tier-Liste jetzt pro Request aus
/shared/config/models.json statt sie hart zu codieren. Neue Tier-Namen oder
angepasste Beschreibungen sind damit eine reine Datei-Aenderung — kein
Code-Edit, kein Proxy-Neubau, kein Neustart (Datei bearbeiten → im Diagnostic
„↻ Aktualisieren").
- Fehlt/kaputt die Datei: eingebaute Defaults greifen und werden einmalig als
models.json angelegt, damit es was zu editieren gibt.
- ids bleiben MODEL_MAP-kompatibel (extractModel), Validierung: nicht-leeres
Array mit String-id, sonst Fallback auf Defaults.
- UI-Hinweis auf den Dateipfad ergaenzt.
- Load/Seed-Logik simuliert verifiziert.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ARIA laeuft ueber das Claude-Max-Abo via CLI — waehlbar ist der Tier, nicht
eine feste Modellversion (die CLI nimmt automatisch das aktuelle Modell des
Tiers). Kein API-Key → keine echte Anthropic-Models-API; daher kuratierte Liste.
- proxy routes.js handleModels: kuratierte /v1/models mit tier/display_name/
description (ids bleiben MODEL_MAP-kompatibel: claude-sonnet-4/opus-4/haiku-4).
- diagnostic server.js: neuer GET /api/models-list — holt die Liste vom Proxy
(Frontend erreicht den Proxy nicht direkt).
- Frontend: Dropdown statt Freitext + „↻ Aktualisieren"-Button; markiert das
aktive brainModel (get_model), zeigt Beschreibung, „Setzen" schreibt brainModel
und weist auf Brain-Neustart hin. Freitext-Override bleibt unter „Erweitert".
Liste wird bei WS-Connect automatisch geladen.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Der /api/files-set-project-Endpoint existierte, aber es fehlte die UI. Jede
Datei-Zeile hat jetzt ein Projekt-Dropdown (Hauptchat + alle Projekte, aktueller
Wert vorausgewaehlt, gruen wenn getaggt). Aenderung schreibt via
/api/files-set-project ins Manifest, aktualisiert den lokalen Cache und rendert
neu (respektiert den aktiven Projekt-Filter).
Damit lassen sich auch alt-hochgeladene (untagged) Dateien nachtraeglich einem
Projekt zuordnen — die projectId-Zuordnung beim Upload passiert automatisch
(596d0bb), das hier ist die manuelle Korrektur/Nachpflege.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Regression aus dem chat_history-projectId-Fix: nach dem History-Reload laeuft
jetzt updateChatVisibilityByFocus(). addAriaFile() setzte aber kein
dataset.projectId → Datei-/Bild-Bubbles galten als Hauptchat und wurden
ausgeblendet, sobald der (aus localStorage wiederhergestellte) Focus auf einem
Projekt lag. In der App trat das nicht auf (datengetriebener Filter mit
korrektem projectId).
- addAriaFile(): setzt dataset.projectId aus p.projectId und respektiert beim
Live-Anhaengen den aktuellen Focus (wie addChat via hiddenByFocus).
- chat_history-Renderer: reicht m.projectId an addAriaFile weiter.
- Bridge _process_core_response: haengt turn_pid als f["projectId"] an die
file_from_aria-Payload, damit der Live-Pfad die Zuordnung kennt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Der Reload-Pfad des Dashboards warf die Kontext-Zuordnung an ZWEI Stellen weg,
weshalb nach jedem Reload alles im Hauptchat lag (Projekte leer) — unabhaengig
davon ob chat_backup korrekt getaggt war:
- server.js (History-Builder): pushte {type,text,meta,ts} ohne project_id.
Jetzt projectId aus obj.project_id fuer sent/received/aria_file mitgegeben.
- index.html (chat_history-Renderer): setzte dataset.ts aber nie
dataset.projectId → jede Bubble galt als Hauptchat. Jetzt gesetzt, und nach
dem Neuaufbau updateChatVisibilityByFocus() aufgerufen damit der aktuelle
Kontext-Focus sofort greift.
Zusammen mit der Backfill-Migration (8b567e1) erscheinen alt-getaggte Turns
jetzt beim Dashboard-Reload im richtigen Projekt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Das Dashboard hatte dieselbe Ursache wie die App (untagged Nachrichten in
chat_backup) PLUS zwei eigene untagged-Pfade ueber den Gateway-Watch:
- Frontend: chat_final rendert keine Chat-Bubble mehr. ARIA-Antworten kommen
ausschliesslich via rvs_chat (traegt projectId). chat_final stammt vom
Gateway-Watch ohne projectId → erzeugte eine Duplikat-Bubble im Hauptchat.
- server.js: kein chat_backup-Write im Gateway-final-Handler mehr. Die Bridge
(_process_core_response) ist massgeblicher Writer und schreibt MIT project_id;
der Write hier erzeugte untagged Duplikate, die beim Reload im Hauptchat
statt im Projekt landeten.
Der App-Focus-Fix (63dde65) sorgt dafuer dass neue Nachrichten ueberhaupt
getaggt in chat_backup landen — davon profitiert das Dashboard direkt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 3 vom Multi-Threading-Redesign. Diagnostic zeigt einen scrollbaren
Streifen von Kontext-Karten ueber dem Chat (Hauptchat + Projekte), jede
mit Live-Status-Dot. Tap wechselt den Focus, Chat filtert auf diesen
Kontext, Sende-Input laeuft mit der Focus-ID durch Bridge → Brain-Queue.
index.html:
- Neuer <div id="chat-context-strip"> ueber der Chat-Box, horizontal
scrollbar.
- JS: focusedContextId (in localStorage gespiegelt), diagQueueStatus,
diagProjectsCache. renderContextStrip() zeichnet Karten mit Dot
+ Status-Label. switchDiagFocus(id) wechselt Focus + versteckt
Bubbles anderer Kontexte via data-project-id + style.display.
- Polling: /api/brain/projects/queue-status alle 2s, /projects/list
alle 15s.
- addChat: nimmt options.projectId → schreibt data-project-id an die
DOM-Node, versteckt sofort wenn Focus abweicht.
- Chat-Reception-Handler propagiert p.projectId aus dem RVS-Payload.
- testRVS() sendet msg.projectId=focusedContextId mit.
server.js:
- sendToRVS(text, isTrace, projectId): neuer Param, wird in
payload.projectId gesetzt → Bridge routet an /chat body.project_id.
- test_rvs-Handler reicht msg.projectId durch.
Bewusst nicht drin (Follow-up wenn Stefan mag):
- Voller Dashboard-Stack mit stacked Karten die eigene Message-Listen +
Input-Felder haben. Aktuelle Variante ist „Kontext-Strip fuer schnellen
Wechsel + Focus-One-Rendering" — ~90% des UX-Werts mit ~10% des Aufwands.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drei Stefan-Bugs aus dem ersten Deploy-Test plus die fehlenden Polish-
Features fuer die Projekt-Funktion.
Fixes:
- ProjectsBrowser-Spinner-Hang: useRef-Pattern statt useCallback([onActive
Changed]) — Parent uebergibt inline-arrow-Callbacks, neue Identitaet
jedes Render → useCallback recomputes → useEffect refeuert → infinite
Spinner. Fix: Ref-Bridge fuer Callbacks, useCallback mit empty deps.
- ChatScreen Banner: zusaetzlicher × Hauptchat-Button rechts (sichtbar
nur wenn Projekt aktiv) — ein Tap und zurueck zum Hauptthread, ohne
Modal-Umweg.
Features:
- Brain ChatOut.project_id: aktive Projekt-ID NACH dem Turn (kann
durch project_enter/exit-Tools waehrend Turn gewechselt sein). Bridge
liest sie aus dem /chat-Response und haengt sie an jeden ARIA-Chat-
Broadcast als payload.projectId.
- App: ChatMessage.projectId-Feld. User-Bubbles werden mit aktiver
Projekt-ID getaggt vor dem Senden (auch im RVS-Payload). ARIA-Bubbles
kriegen die ID vom Bridge.
- App: Chat-Verlauf rendert aufeinanderfolgende Project-Messages als
einklappbaren Block mit Header (▶/▼ + Projekt-Name + Count). Auto-
Collapse beim Projekt-Wechsel (altes ein, neues aus), Default beim
ersten Render: alle inaktiven Projekte eingeklappt.
- File-Manager Project-Tagging:
- diagnostic/server.js: Manifest /shared/config/file_projects.json
+ /api/files-list returnt projectId pro Datei + neuer Endpoint
/api/files-set-project.
- bridge/aria_bridge.py: nach App-Upload Auto-Tag mit aktivem Projekt
(Brain-Status-Query, best-effort fail-silent).
- App SettingsScreen: scrollbare Projekt-Pill-Reihe als Filter, default
auf aktives Projekt wenn vorhanden, sonst "Alle Projekte".
- Diagnostic: zweites Dropdown im Files-Tab, baut Projekt-Optionen
dynamisch aus /api/brain/projects/list.
Bewusst nicht drin (Folgeschritt):
- Per-File "Projekt zuweisen"-Action (Long-Press / Right-Click)
- Filter-Sync zwischen ChatScreen-Banner und SettingsScreen-Filter
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Projekte sind benannte Thema-Bündel die voice-gesteuert via Brain-Tools
geöffnet/verlassen werden. Default-Mode bleibt der Hauptthread — Projekte
sind eine optionale Bühne. Anchored-not-replaced: App-Open landet immer
im Hauptchat, Projekte sind nur sichtbar wenn aktiv betreten.
Brain:
- projects.py: CRUD + Fuzzy-Find + Active-State-Pointer
(/shared/config/projects.json + active_project.txt).
- conversation.py: Turn.project_id-Feld + window(project_id) Filter.
- agent.py: 6 Meta-Tools — project_create / _enter / _exit / _list /
_summary / _end. chat() liest aktive Projekt-ID, taggt User+Assistant-
Turns damit, filtert das LLM-Window auf Projekt-Kontext und ergaenzt
den System-Prompt um den aktiven Projekt-Hinweis. touch_project pflegt
last_activity_at + turn_count.
- main.py: REST-Endpoints /projects/{status,list,create,switch,
{id}/end,{id}/archive, PATCH /{id}}.
Bridge + RVS:
- aria_bridge.py: project_changed Event-Propagation Brain → RVS-Broadcast
damit App + Diagnostic ihre Banner refreshen.
- rvs/server.js: project_changed in ALLOWED_TYPES.
App:
- brainApi.ts: Project-Type + 6 API-Methoden.
- ProjectsBrowser.tsx (neue Komponente, ~340 Zeilen): Status-Header,
Hauptchat als Erster-Eintrag, Projekt-Liste mit Aktiv-Marker, Long-Press
zum Editieren, Modals fuer Neu/Edit/End/Archiv.
- ChatScreen.tsx: Banner unterhalb des Status-Bars zeigt aktives Projekt
oder „Hauptchat" — Tap öffnet ProjectsBrowser als Modal. Aktive Projekt-
Info wird bei Mount + bei project_changed-Events refreshed.
- SettingsScreen.tsx: Neue Section 📁 „Projekte" zeigt ProjectsBrowser inline.
Diagnostic:
- Neue Sektion im Brain-Tab mit Liste, Aktiv-Marker, Beenden/Archivieren
pro Zeile, Modal fuer Neu. Lädt automatisch bei Brain-Tab + bei
project_changed-Event-Broadcast.
Was bewusst NICHT drin ist (Folgeschritte):
- Per-Message Filter im Chat-Verlauf (zeigt aktuell alle Bubbles, Banner
zeigt Kontext) — App müsste Chat-History per project_id filtern.
- Files-by-Project Tagging.
- Inline-Collapse-Bloecke im Chat-Verlauf.
- Sub-Projekte (Stefan-Entscheidung: weglassen, „Mama-tauglich").
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
App-Seite:
- VoiceIdEnrollment.tsx (neue Komponente, ~370 Zeilen): Status-Karte
(loading/unenrolled/enrolled/error), Sample-Recorder mit Countdown
(4s fest pro Sample), Liste mit einzelnem Loeschen, Save-Button
(disabled bis 5 Samples), Fingerprint-Delete mit Confirm.
- SettingsScreen.tsx: neue Section 🎤 'Stimme einrichten' zwischen
Wake-Word und Sprachausgabe.
- Sample-Format: WAV via audioService.startRecording — wird
whisper-bridge-seitig per wave-Modul gestrippt.
Diagnostic-Seite:
- Neue settings-section 'Voice-ID (Sprecher-Erkennung)': Status-Anzeige
(live ueber voice_id_status_response), Threshold-Slider 0.30-0.70
(persistiert in voice_config.json, broadcast als config-Message),
Refresh + Delete-Button.
- server.js: 2 neue actions (voice_id_status, voice_id_delete),
send_voice_config nimmt voiceIdThreshold mit auf.
Backend:
- speaker_id.py: _normalize_audio_bytes erkennt jetzt WAV-Header
(RIFF/WAVE) und strippt auf rohes PCM — sonst werfen die ECAPA-
Embeddings auf den 44-Byte-Header rein.
- bridge.py: config-Broadcast-Handler setzt voiceIdThreshold auf
speaker_id.DEFAULT_THRESHOLD (wird erst in Phase 3 beim Gating
genutzt, persistiert aber schon).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Stefan's UX-Wunsch: Datei direkt oeffnen ohne Umweg ueber Download.
Plus: in der App fehlte komplett der Per-Row-Download-Button (nur via
Checkbox + Bulk-Download). Beides jetzt gefixt.
App (SettingsScreen.tsx):
- Neue per-Row-Buttons: 👁 Open + ⬇ Download + 🕒 Versionen + 🗑 Loeschen
- Open-Pfad nutzt requestId-Praefix 'open-' im file_response-Handler
→ Datei wird nach CachesDirectory geschrieben (kein Storage-Bloat)
→ FileOpener-Native-Module (Intent.ACTION_VIEW mit MIME) oeffnet
mit dem System-Picker → User waehlt PDF-Viewer / Galerie / Player
- guessMimeFromName-Helper fuer den Intent damit Android die passende
App findet
- Download-Pfad unveraendert ('single-' Praefix), schreibt nach
DownloadDirectory mit Suffix-Inkrement bei Namens-Konflikt
Diagnostic (server.js + index.html):
- Neue Route /api/files-view (gleicher Code-Pfad wie files-download,
aber Content-Disposition:inline + echter MIME-Type statt octet-stream)
- Browser zeigt PDF / Bilder / Text im neuen Tab statt forcierten Download
- 👁-Button in jeder File-Row neben ⬇/🕒/🗑
- Fallback fuer unbekannte MIMEs: octet-stream → Browser bietet Download
Bei beiden Pfaden bleibt der Cache nutzbar: nach App-Open kann der User
die Datei im jeweiligen Viewer behalten; im Browser bleibt sie im Tab.
Stefan-Beobachtung: Wenn man V1 restored, taucht der neue Restore-Commit
als V4 in der Liste auf, mit identischem Inhalt wie V1. Bei mehrfachem
Hin- und Herrestoren wird die Liste schnell unuebersichtlich.
Fix: listVersionsForFile dedupliziert auf Blob-Hash-Ebene. Pro
inhaltlich identischer Datei-Variante wird nur der AELTESTE (= zuerst
in der History entstandene) Commit gezeigt. Restore-Commits werden
damit gefiltert da ihr Blob = der Blob eines aelteren Commits ist.
AKTIV-Marker wandert mit: vergleicht Blob der Working-Copy mit jedem
sichtbaren Eintrag — der Match-Eintrag bekommt isCurrent=true. So
zeigt das UI nach Restore "V1 ist AKTIV" obwohl im git ein neuer
V4-Commit existiert.
Implementation:
- log --format=%H + ls-tree pro Commit → blob-hash sammeln
- rueckwaerts durchgehen (chronologisch aelteste zuerst), seen-Set
dedupliziert
- Reverse fuer UI (neueste-zuerst)
- git hash-object <working-copy> → currentBlob, mit jedem Eintrag
vergleichen fuer den AKTIV-Marker
- blob-Feld aus Response strippen (sieht aus wie zweite Commit-ID)
Audit-Trail bleibt im git intakt — Restore-Commits sind weiterhin
da, nur nicht im UI sichtbar. Falls jemals forensische Untersuchung
noetig: `git log` im /shared/uploads zeigt alle, inkl. Restore-Commits.
Stefan-Wunsch: ARIA-Aenderungen an Dateien sollen vom System (nicht
von ARIA selbst) automatisch versioniert werden. Im Datei-Manager:
Versionen auflisten, einzelne downloaden, oder als neue aktive Version
setzen (Restore = non-destructive neuer Commit).
Implementierung (alles im diagnostic-Container, da der eh schon
File-Handling kann):
1. Dockerfile: apk add git
2. server.js — Auto-Commit-Loop:
- Beim Start: /shared/uploads als git-Repo initialisieren (idempotent;
bestehendes .git wird uebernommen)
- setInterval(30s): git status --porcelain → wenn dirty, add+commit
mit "auto: <ISO-Timestamp>"-Message
- Re-Entrancy-Guard fuer langsame git-Ops
3. server.js — drei neue HTTP-Routen:
GET /api/files-versions?path=X
→ [{hash, ts, subject, isCurrent}] aus git log --follow
GET /api/files-version-content?path=X&hash=Y
→ Binary-Stream der Datei aus diesem Commit (Content-Disposition
attachment mit "name@<short-hash>.ext" als Default-Dateiname)
POST /api/files-version-restore body={path, hash}
→ non-destructive: schreibt alten Inhalt als NEUE Version, neuer
Commit "restore: <path> <- <short>". Aktive Version damit
weiterhin rollback-bar.
4. index.html — Datei-Manager:
- Pro Datei zusaetzlich 🕒-Button neben ⬇/🗑
- Klick zeigt Modal mit Version-Liste (timestamp, short-hash,
'AKTIV'-Marker fuer den jeweils letzten)
- Pro Version: ⬇ Download + ⟲ Restore (mit Confirm)
- Restore broadcasted file_version_restored damit Browser refreshen
Path-Safety: alle Pfade muessen relative-to-uploads sein, kein '..',
kein '/', kein '.git/'. Hash muss [0-9a-f]{7,40}.
.gitignore zunaechst keine — uploads/ ist eh nur User-/ARIA-Dateien,
kein Log-Noise erwartet. Falls Disk explodiert: spaeter ergaenzen.
Step-2 (App-Side via RVS-Messages) folgt im naechsten Commit, sobald
das hier in Diagnostic funktioniert.
Bug-Report Stefan: Datei-Manager in der Android-App kann nichts mehr
herunterladen. Test gegen /api/files-download-zip lieferte 79 Bytes
ZIP (nur Header) statt der erwarteten 26 KB.
Ursache: req.on("close", () => zip.kill("SIGTERM")) sollte den
zip-Subprocess killen wenn der Client mid-stream abbricht. ABER:
req.on("close") feuert in Node.js auch SOFORT nachdem der Request-
Body fertig gelesen wurde — nicht erst bei echtem Client-Disconnect.
Folge: zip wird unmittelbar nach req.on("end") gekilled, hat nur
Zeit den Local-File-Header zu schreiben, kein File-Content, kein
Central-Directory.
Fix: statt req.on("close") nun res.on("close") + res.writableEnded-
Check. Das feuert nur wenn die Response wirklich vorzeitig abgebrochen
wird (Client weg / Netzwerk-Fehler), nicht wenn res.end() durch pipe
sauber durchgereicht wurde.
Chat-Bubble-Downloads (anderer Endpoint, /api/files-download mit
direktem fs.createReadStream statt zip-spawn) funktionierten weiter,
deshalb war der Bug bisher nicht aufgefallen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- /api/agent-stream akzeptiert jetzt ?page=N&perPage=M zusaetzlich zu
?lines=N. page=1 = neueste Eintraege, hoehere Pages = aelter.
Antwort enthaelt page/perPage/pagesTotal/total fuer Client-Nav.
- Live-View hat neuen 📜 Archiv-Button neben Leeren/Auto-Scroll.
- Modal mit PerPage-Selector (50/100/500/1000), «‹›» Navigation und
reload-Button. Pagination-Buttons werden auf den Grenzen disabled.
- renderArchiveLine spiegelt das Live-View-Rendering (Tool-Calls in
cyan, Results in gruen, Thinking kursiv) im Modal-Container.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Zwei kleine Robustness-Verbesserungen:
1) chat_history-Handler im Frontend: jede Bubble jetzt in try/catch. Wenn
eine Bubble bei der Render-Pipeline (escape/linkify/regex-replace) eine
Exception wirft, brach die ganze for-Schleife ab und alle nachfolgenden
Bubbles wurden nicht mehr in den DOM geschrieben — beim Reload sah man
dann nur die ersten N Eintraege und Stefan dachte die letzten Antworten
waeren weg. Jetzt: Fehler-Bubble mit "⚠ Render-Fehler" + console.error,
restliche Bubbles laufen weiter durch.
2) Diagnostic-Server RVS-Reconnect: TLS-Fallback war auch bei reinen
Netz-Fehlern (EHOSTUNREACH, ECONNREFUSED, ENETUNREACH, ETIMEDOUT,
ENOTFOUND, EAI_AGAIN) gefeuert — bringt nichts weil der Server eh tot
ist, generiert aber doppelte Reconnect-Versuche + Log-Spam. Jetzt nur
noch bei wirklichen TLS/Handshake-Fehlern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ARIA hat jetzt das META-Tool oauth_register_provider. Wenn Stefan einen
Service nutzen will, der nicht in den (auf Spotify reduzierten) Defaults
ist, kann sie auth_url/token_url/scopes/client_auth selbst eintragen —
ARIA kennt typische OAuth-Endpunkte (Dropbox, Discord, Notion, Slack,
Zoom, Trello, LinkedIn, Reddit, Twitch) aus ihrem Training. Sie traegt
NUR die URLs ein, client_id/secret bleiben Stefans Job (Diagnostic /
App-UI) — bewusste Trennung damit Credentials nicht im Chat-Verlauf
landen.
DEFAULT_PROVIDERS auf Spotify reduziert — Rest war aktuell ungenutzt
und macht den Code unnoetig "groß". ARIA registriert on-demand.
Diagnostic-UI:
- Custom-Provider zeigen auth_url/token_url/scopes als sichtbare Felder
- Defaults verstecken die Felder hinter "Default-URLs ueberschreiben
(advanced)" damit man die Spotify-URLs nicht versehentlich loescht
- "+ Custom OAuth-Provider hinzufuegen" Button mit Prompts fuer
Name/URLs/Scopes
- 🗑-Icon bei Custom-Services (Service komplett entfernen)
App-UI (neu fuer unterwegs):
- Settings → Sektion 🔑 "OAuth-Apps" zwischen Skills und Protokoll
- OAuthBrowser-Komponente analog zu Trigger/Skill-Browser:
Liste mit Status, Tap → Edit-Modal mit client_id/secret +
Advanced-Toggle fuer URLs. "Autorisieren ↗" oeffnet System-Browser
via Linking.openURL, redirected zur RVS-Callback-Page,
Status-Refresh nach 8s.
- "+ Custom"-Button → Full-Screen-Modal fuer Service-Anlage.
- brainApi um listOAuthServices/getOAuthApps/saveOAuthApp/
deleteOAuthApp/authorizeOAuth/revokeOAuth erweitert.
Workflow ist jetzt: "verbinde mich mit Dropbox" → ARIA registriert
Provider → "trag client_id/secret in Settings ein" → Stefan macht das
in App oder Diagnostic → "Autorisieren ↗" → fertig.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bridge hat seit 5+h still gehangen — Container Up, asyncio idle im
selectors.select(), TCP-Verbindung zum RVS ESTABLISHED, aber keine
Events mehr verarbeitet. Klassischer Fall: NAT-Tabelle/Firewall hat
die TCP-Verbindung still gekillt (kein RST), Linux-Kernel mit Default-
Keepalive (2h idle) hat's nicht gemerkt, und der ws.ping()-Future hat
im Limbo gehangen ohne Exception zu werfen.
Schicht 1 — TCP-Keepalive aufm Socket:
SO_KEEPALIVE=1, TCP_KEEPIDLE=30s, TCP_KEEPINTVL=10s, TCP_KEEPCNT=3.
Halb-tote Verbindungen werden in ~1 min mit ECONNRESET sichtbar statt
nach 2h. Loest 80% der Faelle direkt.
Schicht 2 — Asyncio-Watchdog (_rvs_heartbeat_watchdog):
Separate Coroutine parallel zu _rvs_heartbeat. Letzterer markiert
_last_heartbeat_ok nach jedem erfolgreichen pong. Watchdog checkt
alle 20s: > 60s stale → ws.close() + transport.close() als Notausgang.
Schuetzt gegen ws.ping()-Limbo.
Schicht 3 — File-Based Liveness Thread:
Separater OS-Thread (NICHT asyncio) — immun gegen asyncio-Hangs.
Schreibt /shared/health/bridge_alive periodisch. Wenn
_last_heartbeat_ok > 180s stale: os._exit(1), Docker restart_policy
uebernimmt. Last-Resort wenn Schichten 1+2 versagen.
Plus: chat_history-Render nach Reload bezog nur #chat-box, nicht
#chat-box-fs (Vollbild). Wer im FS-Modus reloaded hat sah eine leere
Box statt der History. Jetzt rendert der Handler in beide Boxen
(gleicher Pattern wie addChat / addAriaFile).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bisher musste Stefan bei OAuth-Flows manuell den Auth-Code aus der
Browser-URL kopieren (redirect_uri war localhost). Jetzt: RVS hat einen
HTTP-Listener auf demselben Port wie der WebSocket, Provider redirecten
nach Auth zu https://{RVS_HOST}/oauth/callback/{service}, RVS broadcastet,
aria-bridge forwarded, Brain matched state + tauscht code gegen Token.
Token-Refresh laeuft automatisch.
- rvs/server.js: hybrid http.createServer + WebSocketServer{noServer}.
Route GET /oauth/callback/{service}, broadcast oauth_callback an alle
Raeume, schoene Dark-Mode-HTML-Antwort an den Browser (Auto-Close 4s).
- bridge/aria_bridge.py: empfaengt oauth_callback, POSTet an Brain
/internal/oauth-callback.
- aria-brain/oauth.py: neuer Manager. Pending-Store mit state+TTL,
Token-Exchange (Basic-Auth oder Body je nach Provider), persistente
Speicherung in /shared/config/oauth_tokens.json (mode 0600),
Token-Refresh wenn <60s Restzeit. Vordefinierte Configs fuer Spotify,
Google, GitHub, Strava, Microsoft.
- aria-brain/agent.py: META-Tools oauth_authorize / oauth_get_token /
oauth_revoke.
- aria-brain/prompts.py: System-Prompt-Block zeigt ARIA die feste
Callback-URL als Quelle der Wahrheit + aktuelle Service-States.
- aria-brain/main.py: HTTP-Endpoints /oauth/services, /oauth/apps,
/oauth/authorize, /oauth/{service}/revoke, /internal/oauth-callback.
- diagnostic: neue Section "OAuth-Apps". Pro Service Karte mit Status,
client_id + client_secret (Passwort-Toggle), Speichern + Autorisieren-
Buttons. Authorize oeffnet Provider-Auth in neuem Tab.
- docker-compose.yml: brain-env um RVS_HOST + RVS_PORT_PUBLIC + RVS_TLS
ergaenzt (Brain braucht die Werte zum Bau der Callback-URL).
- .env.example: RVS_PORT_PUBLIC + Brain-Timeout-Vars (PROXY_TIMEOUT_SEC
+ Connect/Write/Pool) dokumentiert.
- README.md: OAuth-Pipeline + ARIA-Live-Mirror in Diagnostic-Section,
OAuth-Apps in Einstellungen-Tab erwaehnt.
- issue.md: OAuth-Pipeline + Brain-Timeout-Fix als erledigt dokumentiert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Passwort-Feld in der FLUX-Section, mit Show/Hide-Toggle und kurzem
Hinweis-Link zu den HuggingFace-Schritten (Lizenz-Agree + Token-Erzeugung).
Wert wird in voice_config.json persistiert und per config-Broadcast an
die flux-bridge gepusht; dort vor jedem from_pretrained als HF_TOKEN +
HUGGING_FACE_HUB_TOKEN env gesetzt.
HF_TOKEN aus .env.example + docker-compose.yml entfernt. Auch FLUX_MODEL
aus compose raus — Default-Modell kommt jetzt komplett aus Diagnostic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stand vorher in der Sprachausgabe-Card — falscher Ort, weil
Bildgenerierung eigene Domaene ist. Neue settings-section zwischen
Sprachausgabe und Whisper.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Diagnostic loggte konstant '[gateway] Nicht verbunden — kann nicht senden'
weil die UI bei jedem Send-Klick noch versuchte ueber den OpenClaw-
Gateway-Pfad zu schicken. Den gibt's seit Monaten nicht mehr — alles
laeuft via Diagnostic → RVS → Bridge → Brain (HTTP).
server.js:
- sendToGateway() loggt nichts mehr (No-Op, returnt false)
- sendToRVS() raeumt den 'gateway + RVS dual'-Pfad weg, geht direkt
ueber RVS
- 'test_gateway'-Action vom Client wird umgeleitet auf RVS damit alte
Browser-Sessions noch funktionieren
index.html:
- 'Gateway senden'-Buttons (Chat-Test + Vollbild) entfernt, 'Via RVS
senden' umbenannt zu 'Senden'
- Gateway-Tab im Log-Viewer raus, mapSourceToTab leitet evtl. Reste
in den server-Tab um
- testGateway() + testGatewayFS() JS-Funktionen entfernt
- btn-gw-Disable-Logik raus
connectGateway/handleGatewayMessage/gatewayWs/state.gateway im server.js
bleiben als deprecated stehen — kein aktiver Code zugreift mehr drauf,
aber rauswerfen wuerde viele Diffs erzeugen ohne Nutzen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
App-Inbox-Modal:
- ScrollView der Top-Section ('Aus diesem Chat') nestedScrollEnabled=true
- MemoryBrowser darunter in einen flex:1-Wrapper gepackt damit er den
verbleibenden Platz bekommt — ohne den hat seine FlatList intern
null Hoehe gehabt und Scroll-Gestures verschluckt.
Diagnostic Trigger-Tab:
- ✎ Bearbeiten-Knopf pro Zeile (neben Aktivieren/Deaktivieren/Loeschen)
- Modal hat jetzt einen Edit-Modus: Type+Name disabled, Save-Button
zeigt 'Speichern', Modal-Title 'Trigger bearbeiten — <name>'
- Fuer Timer im Edit-Modus ein zusaetzliches Feld 'Feuert am (ISO, UTC)'
damit man den absoluten Zeitpunkt direkt aendern kann (statt 'in X
Minuten ab jetzt' das nur fuer Create Sinn macht)
- saveTrigger() unterscheidet jetzt zwischen Create-Modus (POST
/triggers/timer|watcher) und Edit-Modus (PATCH /triggers/{name})
- openTriggerEdit(name) fuellt das Modal mit Werten aus dem Cache
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>