Commit Graph
20 Commits
Author SHA1 Message Date
duffyduckandClaude Opus 5.5 89cb3a765b feat(llm): Diagnostic zeigt, welches Modell gerade in der Karte liegt
Die Flotte listete "qwen3-4b, qwen3-8b" — das sind die Modelle, die die Box
fahren KANN (llama-swap /v1/models), nicht die geladenen. Ohne groups-Config
liegt immer nur eins in der Karte; ein anderes anzufragen entlaedt es
(gegen llama-swap ausprobiert: A laden, B anfragen → A unloaded).

Der Adapter fragt jetzt llama-swap /running und schickt das Ergebnis in jedem
worker_ping (10 s) und im worker_hello mit; nach einem Modellwechsel sofort.
None = llama-swap nicht erreichbar, [] = nichts geladen — die Anzeige
unterscheidet das ("geladen: ?" vs. "keins geladen").

Diagnostic: das geladene Modell gruen mit "● geladen", die anderen grau mit
Hinweis, dass sie beim ersten Aufruf laden und das geladene verdraengen.

"GPU void": die LLM-Zeile zeigt jetzt LLM_GPU (die Karte von llama-swap) statt
der NVIDIA_VISIBLE_DEVICES des Adapters, die mit der Modell-Karte nichts zu
tun hat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 15:40:17 +02:00
duffyduckandClaude Opus 5.5 864237ff2c feat(llm): Download-Fortschritt beim Modell-Laden — und "Laden" kommt endlich an
Eigentlicher Fehler zuerst: llm_provision_model/_result und llm_remove_model
standen nie in der RVS-Allow-List. Der RVS verwirft unbekannte Typen mit einem
stillen return — jeder Klick auf "Laden" im Modell-Katalog ist seit Stage D
(19.09.) an dieser Liste gestorben, die Box hat nie davon erfahren. Laden
liessen sich nur die Modelle aus der Basis-Config der Box.

Gefunden, weil grep rvs/server.js fuer eine Binaerdatei hielt und still
uebersprang: in Zeile 164 stand seit a7998bcd ein ECHTES Nullbyte im
Template-String statt eines Escapes. Node stoert das nicht, aber git zeigte
fuer jede Aenderung am RVS nur noch "Binary files differ". Jetzt \u0000 —
zur Laufzeit derselbe String.

Fortschritt: llama.cpp zieht das GGUF per -hf selbst und meldet nichts. Der
llm-adapter fragt vorab bei Hugging Face, welche Dateien (Groesse, sha256)
kommen, und misst genau diese im HF-Cache-Layout, das llama.cpp verwendet:
  /models/models--org--repo/blobs/<sha256>.downloadInProgress  (waechst)
  /models/models--org--repo/blobs/<sha256>                     (fertig)
Layout gegen den echten llama.cpp-Server ausprobiert, nicht angenommen. Geht
auch bei gesplitteten Modellen und zwei Downloads gleichzeitig; Fallback fuer
aeltere Layouts ueber alle *.downloadInProgress. Phasen: queued → start →
download (%, MB/s, Restzeit) → load ("laedt in die Karte") → ready ("in Karte
N geladen", Name + VRAM aus nvidia-smi) bzw. error.

Mitgefixt: der Warmup wartete LLM_TIMEOUT_SEC (Default 60 s). Ein Modell mit
mehreren GB meldete deshalb "Fehler", waehrend llama-swap weiterlud. Jetzt
LLM_WARMUP_TIMEOUT_S (1900 s, ueber llama-swaps healthCheckTimeout).

Diagnostic: Knopf "⬇ Downloads" neben "Von HuggingFace aktualisieren" mit
Zaehler fuer laufende; "Laden" oeffnet das Fenster direkt. Der Server merkt
sich den Stand pro (Box, Modell), ein spaeter geoeffneter Tab sieht laufende
Downloads. Antwortet die Box nicht, steht nach 30 s eine Warnung da statt
nichts.

Compose (KI-Box): llm-adapter bekommt LLM_GPU (Karte fuer die Meldung) und
HF_TOKEN (Dateiliste gesperrter Repos).

Test: Fortschritt gegen einen echten llama.cpp-Download (Qwen2.5-0.5B Q8,
676 MB): Prozent steigend 0 → 91.6, dann load; zweiter Lauf aus dem Cache
direkt load mit cached=true.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 15:33:54 +02:00
duffyduckandClaude Opus 4.8 5761c5f6b9 fix(xtts): Worker-Neustartschleife — max_size an den RVS angleichen (50MB -> 1500MB)
Ursache der staendigen whisper/f5tts-Neustarts, direkt aus dem Box-Log:
  sent 1009 (message too big) frame with 209221780 bytes
  exceeds limit of 52428800 bytes

Der RVS ist ein BROADCAST-Relay: eine grosse Nachricht (Datei-Transfer,
Voice-Upload, APK-Update) geht an JEDEN Client im Raum. Die aria-bridge nutzt
deshalb max_size=1500MB — die Worker standen auf 50MB (llm-adapter sogar 16MB).
Ein 209-MB-Frame liess sie die Verbindung mit Code 1009 schliessen; danach
TLS-Fallback auf ws:// (scheitert an Caddy), Reconnect, naechster Frame, von
vorn. Ergebnis: Neustart im Minutentakt, und jede laufende Aufnahme war weg —
das ist die eigentliche Ursache fuer 'erste Sprachnachricht kommt nicht durch'.

Alle vier Worker nutzen jetzt RVS_MAX_SIZE_MB (Default 1500), passend zu
RVS/Bridge. Die GPU war NICHT das Problem (4,3 von 8 GB belegt, zweite Karte leer).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-02 01:33:22 +02:00
duffyduckandClaude Opus 4.8 d6c7502810 feat(xtts): OpenAI-Endpunkt fuers lokale LLM + OpenHands-Profil
llama-swap ist bereits OpenAI-kompatibel, war aber nur im Compose-Netz erreichbar
(kein ports-Mapping). Jetzt nutzbar fuer OpenHands, Continue, Open WebUI & Co.

- compose: llama-swap veroeffentlicht 8080 als
  ${LLM_OPENAI_BIND:-127.0.0.1}:${LLM_OPENAI_PORT:-8081} — sicher per Default
  (nur localhost), fuer LAN bewusst BIND=0.0.0.0 setzen.
- llm-adapter: API-Key wird in JEDEN llama-server-Befehl der generierten
  llama-swap-Config eingehaengt (--api-key, shlex-gequotet). Quelle: .env
  (Vorrang) sonst /models/openai_key.json (0600). Neuer Handler
  llm_openai_config setzt ihn zur Laufzeit und lehnt bei .env-Vorrang ab.
  worker_hello meldet Port/Bind/keySet/envLocked — den Key NIE (Broadcast!).
- Diagnostic: pro LLM-Box Endpunkt-Zeile mit Base-URL, Key-Status und Eingabe.
  Bei .env-Vorrang ist das Feld schreibgeschuetzt (🔒). Warnung, wenn im LAN
  offen ohne Key. Der PORT wird nur ANGEZEIGT: er ist ein Docker-Port-Mapping
  und steht beim Container-Start fest — dafuer ist die .env zustaendig.
- rvs: llm_openai_config(_result) in ALLOWED_TYPES (sonst still verworfen).
- Neues Profil 'openhands' (COMPOSE_PROFILES=llm,openhands) mit Port/Bind/Modell
  aus der .env, lokales LLM vorbelegt. Ohne Profil aendert sich nichts.
- .env.example + README: alle Variablen, Sicherheitshinweise (offener Endpunkt,
  Docker-Socket bei OpenHands), curl-Test und wann der Key greift.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-30 22:30:37 +02:00
duffyduckandClaude Opus 4.8 df5cd3be99 fix(rvs-clients): RVS_SNI via getaddrinfo-Override statt host=/port= (HTTP-200-Fix)
Symptom mit RVS_SNI: 'server rejected WebSocket connection: HTTP 200'. Ursache:
die IP stand in der URI -> HTTP-Host-Header = IP -> Caddy findet keinen RVS-Site-
Block (routet nach Host) und liefert eine Default-200-Seite statt WS-Upgrade. Der
vorige Fix korrigierte nur SNI/Cert (server_hostname), nicht den Host-Header.

Zudem: host=/port= als websockets.connect-kwargs kollidieren in der Legacy-API
mit dem aus der URI abgeleiteten Host (TypeError).

Loesung (host-agent, satellite, f5tts/whisper/voxtral/llm-adapter): die URI nutzt
den HOSTNAMEN (RVS_SNI) -> Host-Header + SNI + Cert stimmen; ein In-Process-
getaddrinfo-Override mappt RVS_SNI -> RVS_HOST (IP) fuer den TCP-Connect.
Versionsunabhaengig, nicht-blockierend, nur aktiv wenn RVS_SNI gesetzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-24 17:54:38 +02:00
duffyduckandClaude Opus 4.8 9d93c3fe3d feat(xtts): RVS_SNI in allen Compute-Bridges — AI-Box im RZ-Netz auf interne IP
Damit eine AI-Box (f5tts/whisper/voxtral/llm-adapter) auch im selben Netz wie
der RVS direkt auf dessen interne IP verbinden kann (kein NAT-Hairpin ueber den
externen Hostnamen), ohne am SNI/Cert zu scheitern: RVS_HOST=<ip> + RVS_SNI=<name>.
server_hostname im ssl-Context, gated auf use_tls (respektiert den TLS-Fallback).
Leer = Verhalten wie bisher. Szenario: zweite Box im RZ + eine zuhause.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-24 17:22:27 +02:00
duffyduckandClaude Opus 4.8 3a908d246a fix(fleet): Empfangs-Watchdog in Workern — halb-tote RVS-Verbindung erkennen + reconnect
Root Cause der unsichtbaren Box: die WS-Verbindung wird ueber die Zeit halb-tot
— Caddy (TLS-Terminator vor dem RVS) haelt sie offen und pongt die WS-Pings
selbst, waehrend der rvs-Backend sie laengst fallen liess (rooms:1 = Box nicht
mehr Raum-Mitglied). Die Box sendet worker_hello ins Leere; der WS-Ping erkennt
den toten Backend nie. (Token/URL/Port/IP/RVS-Instanz alle bewiesen identisch.)

Fix: recv() mit Timeout (RX_STALE_S=60s) statt `async for`. In einem echten Raum
kommt staendig Broadcast-Traffic rein (sat_hello alle 25s, Brain-Polling) →
Timer wird laufend resettet. Bleibt der Traffic aus, ist die Verbindung tot →
ConnectionError → Reconnect ueber die bestehende run_loop-Backoff-Logik.
Betrifft alle vier Worker (f5tts/whisper/voxtral/llm-adapter).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 11:10:49 +02:00
duffyduckandClaude Opus 4.8 3474d2eb6f fix(fleet): Worker-RVS-URL ohne /ws — an Bridge/App/Satellit/Diagnostic angleichen
DIE Ursache, warum die Box nie in der Compute-Flotte auftauchte: die vier
xtts-Worker verbanden zu wss://host:PORT/ws?token=… — ALLE anderen Komponenten
(Bridge, App, Satellit, Diagnostic) verbinden ohne /ws (…:PORT?token=…). Das RVS
selbst ignoriert den Pfad, aber der TLS-Terminator vor :444 routet nach Pfad →
/ws landete in einem anderen Endpunkt/Raum. Folge: worker_hello/ping erreichten
den ARIA-Raum nie (rooms:1 = nur ARIA), das Diagnostic sah die Worker nicht (und
das erklaert auch das RVS-Flappen, das NUR die Worker hatten).

Fix: /ws aus der URL aller vier Worker entfernt → gleicher Pfad wie alle anderen
→ gleicher Raum. Danach: Box neu bauen, Worker erscheinen in der Flotte.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 04:47:03 +02:00
duffyduckandClaude Opus 4.8 fc198f90da fix(fleet): worker_hello periodisch wiederholen (wie Satellit) — Box wird nach Diagnostic/Bridge-Neustart wieder sichtbar
Worker sendeten worker_hello nur EINMAL beim Connect. Startet das Diagnostic
oder die Bridge NACH der Box neu, verpassen sie das hello (RVS spielt es nicht
nach) und sehen nur noch worker_ping → die Box taucht nicht in der Compute-
Flotte auf. Der Satellit ist genau deshalb zuverlaessig sichtbar: er wiederholt
sat_hello periodisch.

- alle vier Worker (f5tts/whisper/voxtral/llm-adapter): worker_hello wird jetzt
  zusaetzlich alle ~30s (jeder 3. Ping-Zyklus) wiederholt → ein neu gestartetes
  Diagnostic/Bridge lernt die Box innerhalb von 30s, ohne Box-Neustart.
- diagnostic/server.js: Voice-Reconcile (f5tts) laeuft nur beim ERSTEN/erneuten
  Auftauchen der Box, nicht bei jedem 30s-hello-Resend (sonst Push/Pull-Dauerlauf).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 04:12:16 +02:00
duffyduckandClaude Opus 4.8 51985f7c2e feat(fleet): Auslastungs-Monitor pro Box — live nvidia-smi + Graphen (Stage E)
Pro Box ein "Auslastung"-Button in der Compute-Flotte → Modal mit live
nvidia-smi (1s), Graphen (GPU-Auslastung + Tokens/Intervall) und Besen-Reset.
Historie liegt auf der Box, Diagnostic holt sie via RVS.

- node_stats.py (identisch in allen 4 Worker-Build-Contexts): Sampler alle 15s
  (nvidia-smi + Token-Delta → Ringpuffer ~500 Punkte, persistent als JSON auf
  der Box), Live-Stream (node_stats, 1s, Auto-Stop 300s), History-Request,
  Reset. nvidia-smi via async subprocess, fail-safe ohne GPU.
- Worker-Wiring (f5tts/whisper/voxtral/llm-adapter): Import, Sampler-Task,
  _stats.handle() nach dem targetInstance-Filter. llm-adapter zaehlt Tokens
  (usage.total_tokens) → Token-Graph nur bei LLM-Boxen. Dockerfiles kopieren
  node_stats.py.
- compose: llm-adapter bekommt runtime:nvidia + NVIDIA_VISIBLE_DEVICES=all +
  DRIVER_CAPABILITIES=utility (nur nvidia-smi, KEIN VRAM/Compute).
- diagnostic/server.js: relay node_stats_* (Browser→Box) + forward (Box→Browser).
- diagnostic/index.html: Auslastung-Button pro Node (Ziel bevorzugt llm-Instanz),
  Modal mit live nvidia-smi + Inline-SVG-Sparklines, Besen-Reset.

Reporter-Wahl bevorzugt die llm-Instanz (sieht alle GPUs + Tokens); GPU-Worker
sehen ihre gepinnte Karte. Gitignored Historie stoert git-Baum der Box nicht.
Deploy: diagnostic + GPU-Boxen neu bauen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 03:26:17 +02:00
duffyduckandClaude Opus 4.8 f854303e7b feat(llm): Modell-Download + HuggingFace-Katalog (Stage D)
Neue lokale GGUF-Modelle per Knopf auf eine Box laden — ohne Image-Rebuild.

- llm-adapter besitzt jetzt llama-swaps Config: generiert
  /models/llama-swap.config.yaml aus Basis-Template (xtts/llama-swap/config.yaml)
  + persistenter Registry /models/aria_models.json. Neue RVS-Handler
  llm_provision_model / llm_remove_model (targetInstance-gefiltert): Registry+
  Config schreiben, llama-swap-Reload anstossen, neu announcen, Warmup (zieht das
  GGUF via -hf, Fortschritt via service_status loading→ready). pyyaml ergaenzt.
- compose: llama-swap liest --config /models/llama-swap.config.yaml; llm-adapter
  mountet ./models (rw) + ./llama-swap (ro Template).
- diagnostic/server.js: /shared/config/llm_catalog.json (kuratierte GGUF-Liste)
  + GET /api/llm-catalog + POST /api/llm-catalog/refresh (HuggingFace-API-Merge);
  Actions llm_provision_model / llm_remove_model / llm_test; llm_provision_result
  an Browser durchgereicht.
- diagnostic/index.html: "Modell-Katalog"-Card (HF-Refresh, Ziel-Box waehlen,
  Laden, Verfuegbarkeit) + Test-Chat-Zeile ans lokale LLM (Antwort + Latenz).

Download nutzt llama-swaps vorhandenen -hf-Pfad (kein neuer Download-Code).
Reload ist der einzige Deploy-Verify-Punkt (llama-swap-Image); Fallback Box-up.
Deploy: diagnostic neu bauen (VM) + llm-Boxen neu bauen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 03:12:31 +02:00
duffyduckandClaude Opus 4.8 39426dc70d feat(llm): Flotten-Katalog + modell-bewusstes LLM-Routing (Stage C)
ARIA nutzt lokale LLMs auf mehreren ai-boxen; jede Box (llama-swap) kann
mehrere Modelle fahren. Auswahl nach MODELL, Box wird automatisch gewaehlt.

- xtts/llm-adapter/adapter.py: fragt beim Connect llama-swap GET /v1/models ab
  und meldet die Modell-Liste in worker_hello (models:[...]), Fallback [LLM_MODEL].
- bridge/aria_bridge.py: Worker-Registry speichert models[]; _pick_worker(service,
  model=) beruecksichtigt nur Boxen, die das Modell fahren koennen (nachsichtig:
  keine → None → Broadcast/Claude-Fallback); Round-Robin je service+model
  verteilt mehrere Projekte auf mehrere Boxen; _local_llm reicht das Modell durch;
  _worker_list traegt models[].
- diagnostic/server.js: workers-Map + workerList um models[] erweitert.
- diagnostic/index.html: Compute-Flotte zeigt bei llm die Modell-Liste; das
  "Lokales Modell"-Dropdown wird LIVE aus den angemeldeten Boxen gebaut
  (Vereinigung + kuratierte Namen aus local_models.json, "· N Box(en)"/"offline"),
  darunter eine kompakte LLM-Box-Liste (Node→Modelle→Health). Speisung aus dem
  vorhandenen worker_update-Broadcast.

Kein Brain-/App-Eingriff. Routing greift nur bei aktivem Lokal-Schalter.
Deploy: diagnostic + bridge + llm-Boxen neu bauen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 02:49:30 +02:00
duffyduckandClaude Opus 4.8 254031bb7d refactor: "Gamebox" ueberall durch "AI-Box(en)" ersetzen
Rein terminologisch: die feste "Gamebox" ist konzeptuell zu beliebig vielen
AI-Boxen geworden (Multi-Node-Compute-Fleet). Wort-Sweep ueber Code-Kommentare,
Strings, README, docs, .env.example, CHANGELOG — keine Identifier/Keys betroffen
(Gamebox kam nirgends in Variablennamen vor). Casing erhalten: Gamebox→AI-Box,
gamebox→ai-box. NODE_NAME-Default gamebox→ai-box, Instanz-IDs f5tts@ai-box.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-19 00:34:21 +02:00
duffyduckandClaude Opus 4.8 e39599ecea feat(compute): Redundanz-Routing per targetInstance (Stage 3)
Mehrere Instanzen pro Dienst nutzbar: Anfragen werden gezielt an eine freie
Instanz adressiert statt an alle gebroadcastet. Mehrere f5tts → naechstes
freies; mehrere LLM → parallele Turns (Multitasking); STT-Redundanz ueber
mehrere Apps via Lease.

- Worker (alle vier): filtern am Loop-Eingang — targetInstance gesetzt und
  != eigener INSTANCE_ID → Nachricht ignorieren. Feld fehlt → wie bisher.
- bridge (TTS/LLM, emittiert die Bridge selbst): _pick_worker() waehlt eine
  online+freie Instanz (Round-Robin), stempelt targetInstance auf
  xtts_request / llm_request. Keine Instanz bekannt → Broadcast.
- bridge (STT-Lease, emittiert die App): neuer stt_lease_request-Handler →
  _pick_stt_worker() (voxtral vor whisper) → stt_lease {instanceId}.
- app (audio.ts): requestSttLease() vor dem Stream, stempelt targetInstance
  auf stt_stream_start / stt_audio_chunk / stt_stream_end (+cancel). Kurzer
  Timeout → '' (Broadcast), Aufnahme haengt nie.

Voll rueckwaertskompatibel: Routing aktiviert sich erst, wenn Worker sich per
worker_hello (Stage 2) registriert haben — sonst bleibt alles Broadcast.
Braucht APK-Rebuild fuer die STT-Lease-Seite.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-18 12:27:51 +02:00
duffyduckandClaude Opus 4.8 e255d7a659 feat(compute): Worker-Selbstanmeldung ueber RVS + Flotten-Anzeige (Stage 2)
Jeder GPU-Dienst meldet sich beim Connect mit worker_hello {instanceId,
service, node, gpus, model} und haelt die Registry per periodischem
worker_ping {instanceId, busy} (~10s) frisch. So weiss ARIA, was wo laeuft.

- xtts/{voxtral,whisper,f5tts}/bridge.py + llm-adapter/adapter.py:
  INSTANCE_ID=service@NODE_NAME, _worker_register()-Coroutine (hello + ping),
  busy-Quelle je Worker (aktive STT-Sessions / TTS-Render / in-flight LLM);
  Task sauber gecancelt bei Reconnect.
- bridge/aria_bridge.py: self._workers-Registry + Handler worker_hello/
  worker_ping (spiegelt sat_hello), _worker_list() (35s-Offline-TTL),
  _pick_worker() (Round-Robin freie Instanz, fuer Stage-3-Routing),
  /internal/worker-list-Endpoint.
- diagnostic/server.js: workers-Map, worker_hello/worker_ping-Tracking,
  worker_update-Broadcast + worker_list-Action + on-connect-Snapshot.
- diagnostic/index.html: "Compute-Flotte"-Panel im Satelliten-Tab — pro Node
  gruppiert, mit Dienst/Modell/GPU und frei/beschaeftigt/offline-Status.

Stage 2 von 3. Reine Sichtbarkeit, kein Routing-Verhalten geaendert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-18 12:22:47 +02:00
duffyduckandClaude Opus 4.8 4df6b441ab feat(local-llm): B0.5-2 — Live-Lade-Status des lokalen Modells in Diagnostic
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>
2026-07-11 14:29:18 +02:00
duffyduckandClaude Opus 4.8 f810fc5fca feat(local-llm): B0.5 — llama-swap + lokale Modellauswahl in Diagnostic
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>
2026-07-11 14:11:59 +02:00
duffyduckandClaude Opus 4.8 d772939fb3 feat(local-llm): B1b-Plumbing — tools/tool_calls durch Adapter/Bridge/Brain-Client
Traegt OpenAI-Tool-Definitionen (tools) durch den ganzen lokalen Pfad und gibt
tool_calls zurueck:
- adapter.py: tools -> llama.cpp /v1/chat/completions (tool_choice=auto),
  message.tool_calls zurueck in llm_response.
- aria_bridge.py: _local_llm + /internal/local-llm reichen tools durch, geben
  tool_calls zurueck.
- local_llm.py: local_llm_chat akzeptiert tools, result enthaelt tool_calls.

Inert bis der Brain-Tool-Loop (naechster Schritt) tools uebergibt — Verhalten
unveraendert. Tool-Set + lokale Tool-Loop + Router-Anpassung folgen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 12:36:09 +02:00
duffyduckandClaude Opus 4.8 c06a60d418 fix(local-llm): Qwen3-Thinking im Adapter aus (schnelles Tier grübelt nicht)
Qwen3 hat Thinking default AN -> verbraet Tokens im <think>-Block, liefert bei
kleinem max_tokens leeren content und ist ~3x langsamer (2,2s statt 0,7s im
Test). ARIAs lokales Tier soll fixe Antworten geben, nicht grübeln (grübeln =
harter Turn = Claude). Adapter setzt daher chat_template_kwargs
{enable_thinking:false}; abschaltbar via LLM_DISABLE_THINKING=false.

Verifiziert end-to-end (RVS->Adapter->llama->Qwen3): "Hallo! Ich bin bereit."
in 718ms Round-trip RZ<->Gamebox@home.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 11:05:51 +02:00
duffyduckandClaude Opus 4.8 92615ae46b feat(local-llm): B0 — Gamebox llama.cpp + RVS-Adapter (Provider-Seite)
Plan B, Phase B0 (Provider): lokales Qwen3-8B auf der Gamebox, angebunden
per RVS wie f5tts/whisper (kein IP-Pflegen, nur URL+Token).

- xtts/llm-adapter/: RVS-Client (spiegelt whisper-bridge: TLS+ws-Fallback,
  Reconnect-Backoff), nimmt llm_request, ruft llama.cpp /v1/chat/completions
  lokal, antwortet llm_response (korreliert per requestId). Nicht-streamend
  in B0; llm_partial fuer B2 reserviert.
- xtts/docker-compose.yml: neue Services `llama` (llama.cpp server-cuda,
  GGUF via ./models, OpenAI-API auf :8081) + `llm-adapter`.
- rvs/server.js: ALLOWED_TYPES += llm_request/llm_response/llm_partial.
- GGUF (mehrere GB) via .gitignore aus dem Repo; xtts/models/ mit .gitkeep.

Topologie-Hinweis: Gamebox@home, ARIA@RZ -> Bounce ueber Internet ist
unvermeidbar (Voice macht's schon so); Router faellt bei Nichterreichbarkeit
per Escalation auf Claude zurueck. Consumer-Seite (Bridge-Relay + Brain-
Client + Router) kommt als naechstes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 09:43:46 +02:00