Permet de suivre plusieurs comptes (courtiers/banques) côte à côte, avec vue par
compte et agrégée. Ajoute le PEA BNP Paribas à côté de Revolut.
- portfolio.yaml : nouveau format `accounts` (name/type/cash/positions par compte).
Compat ascendante : ancien format (cash/positions à la racine) lu comme compte
unique « Principal »
- data.py : load_accounts(), base_currency(), portfolio_tickers() (union dédupliquée)
- tracker.py : build_account / build_all (par compte + agrégat global) ; build()
reste la vue globale (digest/report) ; report() multi-comptes
- scanner/technical/alerts : helpers « portfolio » → union de tous les comptes
- dashboard /api/portfolio : renvoie accounts[] (positions+agg par compte) + global
- dashboard front : onglets de comptes (Tous / Revolut / BNP Paribas), KPI + positions
+ secteurs qui suivent le périmètre sélectionné, badge de type par ligne en vue Tous
- BNP Paribas (PEA) saisi depuis la capture : AI/PAEEM/DCAM/PCEU/PSP5/BNP/ENGI/TTE .PA
(tickers Yahoo vérifiés, cours conformes à la capture)
Vérifié : totaux conformes à la capture BNP (6 395,49 € ; P&L -39 €), global 22 444 € ;
bascule d'onglet OK au navigateur (Playwright) ; compile + JS + CLI report OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute une interface graphique à finlab, en plus de la console Claude Code (les
deux cohabitent sur finance.lab.local) :
- dashboard/ : backend FastAPI (sans LLM/clé) exposant les données finlab en JSON
(/api/portfolio, /api/scan, /api/ohlc, /api/plan, /api/alerts) + front statique
(lightweight-charts) : graphiques chandeliers MM50/200 + volume, portefeuille
(P&L/poids/secteurs), watchlists thématiques scannées, alertes, plan de trade R:R
- Découplage code/data : finlab lit ses configs depuis FINLAB_HOME si défini
(workspace persistant) ; repli sur le dossier du package en dév local
- Image double usage (un build, deux conteneurs) : code → /opt/app, seed minimal
(configs + persona + MCP) → workspace
- Fix seed NFS (cause racine du workspace vide) : WORKDIR n'est plus sur le volume
(le runtime le créait en root sur NFS) ; seed déplacé dans un initContainer
robuste (recrée le dossier s'il est non-inscriptible)
- Deployment : initContainer seed + 2 conteneurs (console ttyd -b /console, dashboard
uvicorn) ; Service 2 ports ; IngressRoute 2 routes (/console + dashboard), basicAuth
Validé en local (podman) : seed OK, dashboard /api/portfolio → 16k€/10 positions
via FINLAB_HOME, endpoints ohlc/scan/plan/alerts OK, ttyd/claude/finlab présents.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(finlab): console Claude Code finance in-cluster + toolkit d'analyse
Intègre finlab (ex-projet Projets/Finance) au lab comme une console Claude Code
web spécialisée finance — l'esprit OpenAlice, mais c'est le vrai Claude Code sur
l'abonnement (login persisté, pas d'API facturée), agentique, avec la boîte à
outils finlab (Yahoo Finance) branchée en MCP.
- tools/finlab/ : source finlab rapatriée + Dockerfile (Python 3.12 + Node +
claude-code + ttyd) + persona workspace/CLAUDE.md + branchement MCP + entrypoint
(seed du workspace no-clobber sur le PVC)
- .github/workflows/build-finlab.yml : build GHCR funk-finlab + bump manifest (main)
- k8s/apps/finlab/ : Deployment/Service/PVC/IngressRoute (finance.lab.local) +
Middleware basicAuth (shell web protégé) ; PVC = HOME (login) + workspace
- k8s/apps-of-apps/apps/finlab.yaml : Application ArgoCD
- .mcp.json (racine) : outils finlab dans les sessions Claude Code du lab
- admin/ia/finlab.md + READMEs + CLAUDE.md : doc + enregistrement
Analyse/aide à la décision uniquement — aucun ordre réel (paper trading Alpaca
fictif seul exécutable).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(finlab): ttyd absent des dépôts bookworm → binaire statique GitHub
Le build amont échouait (`E: Package 'ttyd' has no installation candidate`) :
ttyd n'est pas packagé dans Debian bookworm. On récupère le binaire statique
(musl, pin TTYD_VERSION=1.7.7) depuis les releases GitHub. Build complet validé
en local (podman) : ttyd 1.7.7, claude-code 2.1.195, import finlab + seed OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Projet mis en pause : Kraken via « CCXT Custom » non supporté (fetchBalance
avorte) + pas d'automatisation actions. Pod éteint, mais Deployment + PVC
openalice-data (config, clés scellées, données) conservés. Relance = replicas 1.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Le Dockerfile amont v0.60.0-beta.1 copie src/workspaces/templates dans l'image
runtime mais oublie src/workspaces/cli, alors que cliBinPath()
(/app/src/workspaces/cli/bin) est requis au runtime pour poser les shims
alice/alice-uta/traderhub sur le PATH des agents. Sans eux, l'agent ne peut pas
joindre le moteur de trading ("alice-uta introuvable sur mon PATH").
- build-openalice.yml : patch du Dockerfile cloné (COPY src/workspaces/cli) + guard
- tag image suffixé via IMAGE_PATCH=p1 → nouveau tag immuable, ArgoCD redéploie
- deployment.yaml → :v0.60.0-beta.1-p1
- doc admin/ia/openalice.md (correctifs locaux)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Déploie TraderAlice/OpenAlice (AGPL-3.0) dans le namespace ai comme back-end de
connaissances financières pour Asa, consommé via le connecteur MCP Ask.
- CI build-openalice.yml : rebuild depuis le Dockerfile amont (ref épinglée v0.60.0-beta.1)
→ ghcr.io/alkatrazz24/funk-openalice, bump manifest sur main
- k8s/apps/openalice : Deployment (restricted + fsGroup, Recreate), PVC 5Gi NFS /data,
Service web:47331 + mcpask:3003, IngressRoute openalice.lab.local
- ArgoCD app + doc admin/ia/openalice.md (RAG) + MAJ CLAUDE.md
- Cerveau hybride : LiteLLM/Qwen3-8B local (gratuit) + Claude basculable ; données
TraderHub (sans clé) + FMP gratuit. Lecture/recherche seule — aucun broker, zéro trading.
Onboarding premier boot (Web UI) imposé : credentials scellés dans /data par design.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
La page détail d'un service (panneau « Services » du HUD) passe en PLEINE
PAGE : le drawer prend tout l'écran, le titre devient le nom du service, et
le contenu s'organise en 2 colonnes sur grand écran (données à gauche, état
+ actions à droite).
Nouvelle section « Métriques » par service, config-driven (comme `components`) :
- `[[services.metrics]]` → {label, prom, unit, hide_if_empty} évalué par le
StatusPoller (dédup + parallèle avec les composants).
- Défauts via `config._pod_metrics(ns, pod_re)` pour les 7 services : redémarrages
+ uptime (kube-state-metrics, toujours dispo) ; mémoire + CPU (cAdvisor,
`hide_if_empty` → carte masquée si non scrappé).
- Formatage HUD par unité : duration (8 j 9 h), bytes (497 Mo), cpu (30 mcœur),
count.
Client 0.19.0. PromQL vérifié live (les 4 métriques renvoient des valeurs réelles
sur les 7 services). Rendu pleine page + formats validés via Playwright.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Les pages détail du portail HUD affichent désormais un aperçu live des données
du service, pas seulement santé + lien :
- Ghostfolio → portefeuille complet : valeur, performance globale, positions
(allocation % + P/L par ligne, coloré). Nouvel endpoint serveur
POST /v1/portfolio/details (jeton client, source unique réutilisée).
- Alertmanager → TOUTES les alertes actives du homelab (total + critiques +
liste avec sévérité), rendu côté HUD depuis `all_alerts` poussé par le
StatusPoller (auto-rafraîchi, aucun appel supplémentaire).
Mécanisme extensible (`DETAIL_PROVIDERS` : `server` = requête backend |
`alerts` = liste locale). Cartes de stats + lignes de données génériques.
Client 0.18.0. Vérifié via Playwright (rendu, tons, normalisation des %).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Deux demandes côté client :
- VOLUME : slider « Volume de la voix » (0–200 %) dans le drawer Réglages du HUD,
appliqué À CHAUD (canal settings → engine.cfg.tts_volume) et persisté
(localStorage). Gain appliqué au WAV avant lecture, commun Piper/Kokoro
(engine._apply_gain, PCM16 ×gain, clip). Config [voice].tts_volume (0.0 muet …
2.0 amplifié, défaut 1.0). 0 = muet (le tour se déroule sans son).
- FENÊTRAGE : le mode existait ([ui].window_mode app|kiosk|none) ; `stt --window`
PERSISTE désormais le choix → `stt --window app` rend le HUD fenêtré (déplaçable/
redimensionnable, type Discord) durablement, y compris pour le service systemd.
Client 0.17.0. Doc : stt.example.toml + admin/ia/stt.md. Validé : gain ×0.5 exact,
HUD sans erreur JS (slider + collectSettings + label live).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Relevé live 2026-06-23 → mise à jour des écarts depuis le 21/06 :
- admin/ops/etat-cluster.md : SearXNG ajouté (ns ai deploy/svc/IngressRoute,
Application ArgoCD), date + note « STT devenu agentique ».
- CLAUDE.md : date d'état → 23/06 ; bullet STT réécrit (Asa agentique : contexte
asa par défaut, function calling, état live enrichi GPU, web_search, admin_action,
TTS Piper|Kokoro) ; nouveau bullet SearXNG ; apps-of-apps + apps + namespaces
incluent searxng.
- admin/ia/stt.md : corrige les mentions « agir via Hermes = à venir » (désormais
FAIT via admin_action/hermes-exec) ; bandeau daté complété (21→23/06).
(Re-ingestion RAG à faire après merge.)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Faciliter le changement de voix (le simple --update ne bascule rien : la config
perso prime sur le défaut).
- `stt --voices` : liste les voix Piper FR (homme/femme), URLs vérifiées sur
HuggingFace rhasspy/piper-voices.
- `stt --install-voice fr_FR-tom-medium` : télécharge .onnx + .onnx.json et
SÉLECTIONNE la voix (écrit tts_engine=piper + piper_voice dans stt.toml, en
préservant les autres réglages). Puis `stt --restart`.
- doc : admin/ia/stt.md (note « pourquoi --update ne change pas la voix »).
Client 0.16.0.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute un moteur TTS plus naturel (Kokoro, ONNX/CPU) au choix, Piper restant
le défaut et le repli.
- engine.py : synthèse enfichable (_synthesize → _synth_piper | _synth_kokoro).
Kokoro chargé une fois (préchargé au boot si sélectionné), WAV via wave stdlib
(numpy → PCM16), lecture/interruption inchangées. Repli SILENCIEUX si le modèle
ou le paquet kokoro-onnx manque (jamais de crash).
- config : [voice].tts_engine ("piper"|"kokoro") + kokoro_voice (ff_siwis, FR),
kokoro_speed, kokoro_lang.
- cli : `stt --install-kokoro` télécharge kokoro-v1.0.onnx + voices-v1.0.bin dans
~/.local/share/kokoro et imprime les étapes (pipx inject kokoro-onnx, espeak-ng).
- pyproject : extra optionnel [kokoro] ; client 0.15.0.
- doc : stt.example.toml + admin/ia/stt.md + journal.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Asa peut désormais AGIR sur le homelab quand on le demande explicitement, via
un outil de la boucle agentique — mais jamais sans confirmation.
- Outil admin_action(description) (contexte asa) : le LLM PROPOSE une action,
n'exécute rien. brain.ask_with_tools gagne `confirm_tools` : un tel outil
arrête la boucle et surface sa réponse (la question de confirmation).
- _handle_agentic : stocke la proposition en pending par session ; au tour
suivant « confirme » → agent.run_action → hermes-exec (hermes -z --yolo),
« annule » → oubli. Réutilise le handshake + jeton du contexte agent.
- admin_action n'est exposé que si _actions_available() (STT_ACTIONS_ENABLED
+ jeton) ; sinon retiré des schémas envoyés au modèle.
- Factorisation du ctx_debug du visualiseur. 1 test unitaire (confirm_tools
arrête la boucle). Serveur 0.9.0 ; doc stt.md + journal.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Asa ne répondait qu'à partir d'un contexte figé (RAG doc ou blocs live
pré-câblés, à présélectionner) → les questions à état live (« gpu-01 tourne
bien ? ») tombaient sur « la doc ne le précise pas ». Bascule vers une boucle
de function-calling : le modèle décide quels outils appeler puis répond à
partir de leurs résultats.
- Nouveau contexte `asa` (STT_DEFAULT_CONTEXT=asa, défaut prod) + tools.py
(registre schémas OpenAI + exécuteurs) + brain.ask_with_tools (boucle bornée
STT_TOOL_MAX_ITERS=4, réponse forcée au-delà ; _post factorisé + retry).
- Outils Phase 1, LECTURE SEULE : search_docs (RAG funk-docs), host_health
(gpu-01|storage-01 : up/charge/RAM + llama-server), cluster_status,
prometheus_query (PromQL arbitraire). Réutilisent sources.py / knowledge.py.
- Trace des outils renvoyée dans `context` → visualiseur HUD (un bloc par appel).
- 100 % local (Qwen3-8B) : tool-calling natif llama.cpp validé, survit au
/no_think. LiteLLM transmet bien les tools. PromQL validés contre le vrai
Prometheus in-cluster. 3 tests unitaires de la boucle (hors-ligne).
Web search (SearXNG in-cluster) = Phase 2 ; actions admin pilotées par le LLM
(hermes-exec comme outil) = Phase 3.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Le `dnf upgrade` du rôle common avait bumpé gpu-01 en AlmaLinux 9.8, mais
repo.radeon.com ne publie pas latest/rhel/9.8 (ni 9.5) — seulement 9.4/9.6/9.7.
`make apply-gpu` échouait alors dès `common` sur « Cannot download repomd.xml »
pour le repo amdgpu.
- rocm_rhel_version 9.4 → 9.7 (dernière mineure publiée par radeon) + piège
documenté dans le README rocm (avec workaround live /etc/dnf/vars/amdgpudistro).
- Pin llama_server_commit au commit construit sur g01 : sans pin le rôle clonait
HEAD → rebuild (~15 min) + restart GPU non déterministe à chaque apply.
- Réconciliation du drop-in llama-embed (ubatch 2048) dans l'unit rendu par le
rôle (apply ciblé) ; drop-in temporaire supprimé. RAG validé (rag-query OK).
- Doc : etat-cluster + journal 2026-06-22 mis à jour.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Test sur poste après #45 : Parakeet FR ne transcrit pas « Asa » comme un mot mais comme
« a so » / « à ça » / « ah ça » (deux tokens) → la détection mot-entier ne matchait jamais
(« quand je dis Asa, rien ne se passe »).
- _detect_wake : glisse une fenêtre de 1-2 mots, joint (sans espace) + déaccentue, compare
en égalité exacte à des alias COMPACTS (asa, aso, aca, ahca…). L'exact évite les faux
positifs (« à cause » → « acause » ≠ alias). Extrait la commande après le wake.
- wake_aliases (engine + config) : formes compactes reflétant les rendus ASR réels.
- Log diagnostic [stt.voice] sur stderr/journalctl (transcription + décision), coupable via
STT_VOICE_LOG=0 — précieux pour ajuster les alias selon l'ASR.
- .gitignore : build/ + *.egg-info (artefacts d'install locale du client).
Validé en live (poste) : « Asa » réveille, « Asa stop » endort, partiels en direct.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(rag): ubatch=2048 pour llama-embed + retry rag-ingest + nettoie defaults rag
L'instance llama-embed (:1238) tournait avec l'ubatch llama.cpp par défaut (512).
En mode --embeddings + pooling, toute l'entrée doit tenir dans un seul ubatch →
tout chunk > 512 tokens échouait en HTTP 500 « input too large to process.
increase the physical batch size ». ~46 chunks du RAG (CHUNK_MAX=2000 chars ≈
700 tokens) n'étaient pas indexés.
- llama_server : ajoute llama_embed_ubatch_size (2048 = ctx) + flags
--batch-size/--ubatch-size dans le template llama-embed.service.
- rag-ingest : retry (5×, backoff) sur erreurs transitoires 5xx/réseau de l'embed.
- rag/defaults : aligne embed_url/embed_model sur nomic :1238 (étaient des vars
mortes pointant encore qwen3-8b :1234 — trompeuses).
Résultat : ré-ingestion 436/436 chunks, 0 erreur.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(cluster): aligne la doc sur l'état réel (relevé 2026-06-21) + snapshot
Passe de vérification terrain (SSH s01/g01 + kubectl) pour corriger les écarts
doc↔réalité, et ajout d'un document de référence vérifié.
- admin/ops/etat-cluster.md (nouveau) : snapshot daté — machines, services+ports
par hôte, workloads k8s, namespaces, IngressRoute, bases PG, modèles LiteLLM,
RAG/Qdrant, + procédure pour régénérer le relevé.
- OS AlmaLinux 9.7 → 9.8 (s01/g01) ; précise k8s v1.33.1 (CLAUDE/README/install/talos).
- RAG funk-docs : retire le warning périmé « supprimée 2026-06-17 / à re-ingérer » →
reconstruite (436 chunks, nomic-embed-text :1238 dim 768, CPU). Maj rag.md,
incidents.md, stt.md.
- Namespace sacrifice (hors-repo, hors ArgoCD) + bases PG grafana/sacrifice +
services ai via IngressRoute + registry in-cluster (CLAUDE.md, k9s.md).
- Services de résilience (llm-heartbeat, llama-watchdog/embed) et instances CPU
manuelles :1236/:1237 (souvent éteintes) documentés.
- Journal progress/2026-06-21.md : section relevé + RAG.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(stt): transcription partielle live + veille/réveil vocal (« Asa » / « Asa stop »)
Deux fonctionnalités sur l'assistant vocal Asa (client 0.13.0 → 0.14.0).
Transcription partielle live :
- en éveil, le buffer en cours est re-transcrit périodiquement (partial_interval_sec) et
poussé au HUD (event `partial`) → le texte se forme en direct dans une bulle dédiée,
remplacée par la bulle « user » finale.
- auto-activée seulement avec l'ASR onnx (Parakeet, rapide CPU) ; bornée min/max ;
forçable via [voice].partial_transcription.
Veille / réveil vocal (machine à états asleep ↔ éveil) :
- veille : Asa transcrit chaque énoncé UNIQUEMENT pour repérer le wake word, ne répond à
rien d'autre (HUD : portrait atténué, « SOMMEIL »).
- « Asa » (mot entier, alias ASR tolérés) réveille ; « Asa, <question> » exécute la question.
- « Asa stop » (ou stop/dors/au revoir… = sleep_words) remet en veille ; timeout aussi.
- wake word par défaut `asa` (était `hermes`) ; détection durcie en mot entier (plus de
sous-chaîne — « asa » matchait « casa », « phrase »…).
Validé : tests unitaires (wake/sleep/alias) + Playwright (rendu asleep, bulle partielle mise
à jour en place puis remplacée, nettoyage au changement d'état). Doc admin/ia/stt.md + journal.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Asa peut AGIR sur le homelab (l'autre moitié de la vision), via le vrai agent Hermes,
profil par défaut, tous ses outils — avec confirmation et jeton.
Découverte : Hermes n'a pas d'API HTTP (appli TUI), mais un mode one-shot `hermes -z
"<prompt>" --yolo`. On s'appuie dessus.
storage-01 — exécuteur :
- tools/hermes-exec/server.py : service HTTP qui lance `hermes -z --yolo` en user hermes,
derrière un jeton Bearer (compare_digest), timeout + audit, une action à la fois.
- rôle Ansible hermes_exec : systemd (User=hermes, env hermes-agent), jeton via
EnvironmentFile 0640 (Vault vault_hermes_exec_token) ; ajouté au playbook storage-01.
STT-server (0.5.0 → 0.6.0) :
- agent.py : pont vers hermes-exec (jeton) + détection confirme/annule.
- contexts.py : contexte « agent » (court-circuite le LLM).
- app.py : flux dédié — handshake 2 temps par session (pending action) → sur « confirme »,
appelle hermes-exec ; « annule » annule. /v1/contexts masque « agent » si désactivé.
- config : STT_ACTIONS_ENABLED (opt-in, défaut false) + URL + jeton (secret k8s).
- deployment : env actions + secret stt-server-secrets/hermes-exec-token (optionnel).
Sécurité : opt-in désactivé par défaut ; jeton obligatoire (sinon contexte caché + exécuteur
refuse tout) ; --yolo atteint seulement jeton+confirmation en main ; audit storage-01.
Client : AUCUN changement (le contexte « agent » apparaît tout seul dans le sélecteur).
Validé en local : exécuteur (401 sans/mauvais jeton, exec avec bon jeton via echo),
handshake serveur (TestClient : confirme→exécute, annule→annule, agent masqué si OFF).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Deux features mergées n'avaient pas atteint main (effet de bord des PR empilées :
#37 a été mergé dans sa branche de base supprimée, jamais propagé). Recollées proprement
sur main à jour, en fusionnant engine._respond / app.py avec le travail contextes (#39).
Intents vocaux (lecture seule, court-circuitent le LLM) :
- portal/intents.py + ghostfolio.py (récupérés) + exports __init__.
- engine.py : intent_router AVANT le LLM ; cohabite avec context_provider
(pas de contexte émis sur un intent local).
- app.py : construit le routeur (services, ouverture, santé, Ghostfolio).
- config : section [ghostfolio] + doc example.toml.
Affichage version :
- app.py : meta_msg poussé à la connexion.
- hud : case 'meta' + setVersion + ligne « Version installée » (section Service).
- bump 0.11.0 → 0.12.0.
Validé : compile, routage intents, coexistence intent/visualiseur dans _respond
(intent → mode portail sans contexte ; LLM → contexte émis), HUD (meta/version).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Asa n'est plus bloqué sur le seul contexte « doc cluster grounding-strict ». Le client
choisit un contexte par requête ; le serveur change le system prompt ET injecte les
données live du domaine, puis renvoie le contexte assemblé pour le visualiseur du HUD.
- contexts.py : profils funk / ghostfolio / grafana / alerting / cluster (system prompt
+ sources) + assemble() (prompt final + structure de visualisation).
- sources.py : fetchers live best-effort (Ghostfolio auth+details, Alertmanager alerts
hors Watchdog, Prometheus cluster/metrics), env-config, dégradation propre.
- brain.py : ask() reçoit le system prompt déjà assemblé (assemblage remonté).
- app.py : /v1/ask accepte `context`, renvoie context_id + le contexte assemblé ;
nouveau GET /v1/contexts ; RAG doc conditionné au profil.
- config.py : URLs sources + STT_GHOSTFOLIO_TOKEN + STT_DEFAULT_CONTEXT.
- deployment : env in-cluster (Prometheus/Alertmanager monitoring, Ghostfolio ai),
jeton via secret optionnel stt-server-secrets/ghostfolio-token.
- bump 0.3.1 → 0.4.0.
Validé en local : assemblage (blocs+RAG+mémoire), parsing des sources (mock),
endpoints /v1/contexts et /v1/ask (LLM mocké) — context_id, visualiseur, fallback
contexte inconnu → funk.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute la gestion du service STT directement depuis l'interface (Réglages →
section « Service ») et deux commandes CLI.
- CLI : `stt --start` (démarre le service) et `stt --restart` (recharge la config :
modèle ASR, wake word…). Garde-fou si le unit n'est pas installé.
- HUD : boutons Redémarrer / Mettre à jour / Arrêter. Le HUD tournant DANS le
service, les actions sont lancées en process détaché (start_new_session) → le
redémarrage va à son terme même quand le process courant est tué (systemd
possède le job). « Mettre à jour » = `stt --update` puis `stt --restart`.
- bump 0.8.0 → 0.9.0.
Validé : py_compile, --start/--restart dans l'aide, et HUD via Playwright
(3 boutons émettent service-restart/-update/-stop, toast, aucune erreur JS,
rendu conforme).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Ajoute un panneau « Services » au HUD du client STT : une tuile par service du
homelab (Ghostfolio, Grafana, ArgoCD, n8n, Open WebUI, Prometheus, Alertmanager,
Traefik), un clic ouvre l'URL dans le navigateur habituel.
- stt/portal/ : registre piloté par [[services]] de stt.toml (id, name, url, icon,
aliases) + résolution floue (registry.match_service) prête pour la voix.
Ajouter un service = quelques lignes de config, zéro code.
- config.py : défauts homelab + doc dans stt.example.toml.
- ui/app.py : pousse la liste au HUD à la connexion, action de contrôle
open-service → _open_url_external (xdg-open, session navigateur normale) + toast.
- hud/index.html : bouton header, drawer Services (voile partagé avec Réglages),
grille de tuiles, toast de confirmation.
- bump 0.7.0 → 0.8.0.
Validé : registre (fuzzy-match FR/fautes/négatif), wiring backend, et HUD via
Playwright (rendu tuiles + clic émet open-service + toast, aucune erreur JS).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Hermès répondait « la doc ne le précise pas » à « combien de nœuds K8s + OS »
alors que talos.md § Architecture contenait l'info — mais en TABLE : nomic embed
mal une table face à une question en langage naturel (pas de « 3 »/« trois », OS
implicite), donc le chunk ne remontait pas dans le top-k.
Fix = phrase en prose dense en tête de la section (compte explicite + OS + rôles +
les 2 hôtes AlmaLinux hors cluster). Le chunk passe #1 (score 0.743 vs ~0.69 avant).
Validé après re-ingest :
- « combien de nœuds K8s + OS » → « 3 nœuds, tous sous Talos Linux v1.13.0 » (docs=6)
- « combien de machines + OS » → réponse nuancée (3 Talos + 2 AlmaLinux hors cluster)
Leçon RAG : préfixer toute table dense d'une phrase en prose pour l'ancrage des
questions naturelles « combien / quel ».
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Le heartbeat embed (#28) gardait le slot :1238 chargé mais docs=0 revenait :
latence bimodale 16ms / 9-12s. Cause = contention GPU, pas cold-start. nomic
(:1238, --n-gpu-layers 99) partageait la RX 6700XT avec le chat qwen3-8b (:1234) ;
ROCm sérialise → un embed lancé pendant une génération chat attend ~10s → dépasse
le budget recall 4s du STT-server → docs=0 intermittent.
- llama_embed_n_gpu_layers: 99 → 0 (CPU). nomic = 137M → ~100ms déterministe,
découplé du slot chat. Le template lit déjà la variable.
- heartbeat embed conservé comme sonde de vivacité (commentaire ajusté).
- incidents-llm-gpu.md : section dédiée + README rôle mis à jour.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sur un sujet absent de la doc Funk, le 8B comblait le vide en devinant
(« j'ai un switch ? » → tantôt « Oui » tantôt « Non », fausse assurance).
Le grounding marche (docs=6) mais la doc n'a rien à ancrer.
- config.py : system_prompt durci — si la doc ne mentionne PAS explicitement
l'élément, répondre « la doc Funk ne le précise pas », ne jamais affirmer
oui/non par déduction ni inventer de détail (modèle, marque, nombre, nom).
- admin/infra/reseau.md : section « Topologie physique — switch cluster »
(switch présent, modèle à confirmer) → comble le gap doc qui causait
l'hallucination sur le matériel réseau.
- bump 0.3.0 → 0.3.1
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Le grounding RAG du STT ratait par intermittence (docs=0 → réponses génériques)
parce que l'instance d'embedding :1238 partait à froid après une pause : la 1ʳᵉ
requête mettait 5-8 s et dépassait le timeout 4 s du STT-server (recall + RAG doc).
llama-embed-heartbeat : service systemd local sur gpu-01 qui envoie un petit embed
à :1238 toutes les 20 s → le slot reste résident/chaud → la 1ʳᵉ vraie requête est
rapide → docs>0 fiable. Pendant du llm-heartbeat (slot chat :1234), pour le slot embed.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sans contexte, le modèle (qwen3-8b) hallucinait sur le homelab (« stockage
décentralisé », « worker nodes »…) car il ignore tout du cluster réel. Le
cerveau interroge désormais la collection funk-docs (la doc admin/ indexée) et
injecte les passages pertinents au prompt → il répond à partir de la vraie doc.
Coût ~nul : funk-docs et stt-memory partagent le même embedder nomic (:1238,
768 dim) → le vecteur de requête calculé pour le recall mémoire est réutilisé
pour la recherche doc (une embed, deux recherches). Dégrade en silence si
Qdrant/embed down (réponse sans doc plutôt qu'échec).
Module knowledge.py (STT_DOCS_RAG, TOPK=6, MIN_SCORE=0.45). Log /v1/ask
expose docs=<n>. Serveur 0.2.1 → 0.3.0.
Validé : « c'est quoi le nom des nœuds ? » → avant « worker/master nodes »
(inventé) ; après « Kubernetes ; nœuds storage-01, compute-01, compute-02 »
(tiré de la doc).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(rag): exclure hermes/builtin de l'index funk-docs
Les rapports auto-générés par hermes-auto-improve (admin/hermes/builtin/,
"ne pas éditer") représentaient ~84% des points de la collection et noyaient
la vraie doc → rag-query remontait du bruit. On les élague à l'ingestion
(os.walk), surchargeable via RAG_EXCLUDE. Collection re-bâtie : 403 points
propres (0 builtin), rag-query remonte de nouveau les bons documents.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(stt-client): boutons stop réponse + mute micro (HUD) + `stt --stop`
HUD : deux contrôles dans la barre du haut.
- « stop » coupe la réponse en cours — interrompt la lecture TTS (kill aplay)
et saute la synthèse si pressé pendant la génération (Event _interrupt).
- « micro » coupe/réactive l'entrée audio (la boucle VAD ignore les trames) ;
l'état fait foi côté backend, renvoyé au HUD via {"type":"mic"} (ré-émis à
la connexion d'un nouveau client).
Protocole WS : nouveau message {"type":"control","action":"stop|mute|unmute"}.
CLI : `stt --stop` éteint le service — systemd --user (stt.service) si actif,
sinon SIGTERM aux process vocaux trouvés via /proc (s'exclut + ignore les
sous-commandes utilitaires).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(litellm): heartbeat anti-502 + request_timeout 20s
Cause racine du 502 « 1ʳᵉ demande après une pause » : la connexion keep-alive
LiteLLM↔llama-server devient inactive → llama-server la ferme → LiteLLM garde le
socket mort → la requête suivante part dans le vide → timeout → 502.
- llm-heartbeat : service systemd qui appelle hermes-default toutes les 15s
(max_tokens:1, /no_think → ~10ms GPU) → la connexion n'est jamais inactive,
jamais périmée. Logge les échecs → sert aussi de sonde (vraie génération).
- request_timeout 60→20s : un socket périmé échoue vite, dans la fenêtre où
num_retries:2 peut rejouer sur une connexion neuve (sinon le client abandonnait
avant le retry → 502 sec).
- Doc : admin/incidents-llm-gpu.md (fix racine) + README rôle.
⚠️ heartbeat appelle hermes-default en continu → si bascule sur Claude (facturé),
mettre llm_heartbeat_enabled: false. request_timeout global → remonter si Claude.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(llama_server): watchdog auto-réparation du wedge ROCm
Service systemd local sur gpu-01 qui sonde une vraie génération sur :1234
(pas juste /health, qui ment quand le slot d'inférence est figé). Sur N
échecs consécutifs → systemctl restart llama-server en local (root, sans
SSH/sudo distant). Gère le 503 "Loading model" post-restart sans le compter
comme échec.
Complète le llm-heartbeat (rôle litellm) : le heartbeat empêche la péremption
par inactivité de la connexion ; le watchdog répare le figeage du serveur lui-même.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Cause du burst de 502 « cold-start » : après un restart de llama-server, LiteLLM
garde des connexions keep-alive mortes dans son pool → la requête suivante hang
jusqu'au timeout. Or request_timeout valait 600s → hang jusqu'à 10 min, sans log
(LiteLLM attendait encore). Fix :
- request_timeout 60s : borne le hang d'une connexion morte
- num_retries 2 : rejoue → évince le socket périmé, repart sur une connexion neuve
Doc : section dédiée dans admin/incidents-llm-gpu.md (mécanisme + application +
reste à faire = watchdog qui bounce llama-server ET litellm).
Application : ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags litellm
(redémarre LiteLLM → applique le fix ET purge le pool d'un coup).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(stt): auto-start via `stt --install-service` (phase 6)
Ajoute `stt --install-service` / `--uninstall-service` : génère et active un
service systemd --user (lié à graphical-session.target) qui lance le HUD + voix
à l'ouverture de session. Le kiosk existant (ui.kiosk) fournit l'« écran Jarvis ».
- cli : _service_unit (génération du unit, fonction pure testable),
_cmd_install_service (écrit le unit + import-environment DISPLAY/WAYLAND +
daemon-reload/enable/start), _cmd_uninstall_service.
- Docs : admin/ia/stt.md (phase 6 → ✅, section Auto-start + caveat DISPLAY),
stt/README.
- Bump client 0.2.1 → 0.3.0.
Phase 6 de la roadmap STT. Reste : test sur poste, outils Hermes (7).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
* feat(stt): app de bureau (fenêtre type Discord) + auto-update
Rend STT lançable comme une application de bureau et ajoute la mise à jour intégrée.
- Mode fenêtre « app » : _open_browser ouvre le HUD en fenêtre chromeless
(--app=, type Discord) en plus du kiosk plein écran ; support Brave ajouté.
Sélection via --window {app,kiosk,none} ou [ui].window_mode.
- stt --install-desktop / --uninstall-desktop : entrée .desktop + icône
(stt/hud/icon.svg, aussi favicon du HUD) → STT dans le menu/dock, lance --window app.
- stt --update : pipx reinstall depuis la source git (via clé SSH), affiche
« ancienne → nouvelle » ; stt --version.
- Docs (admin/ia/stt.md, stt/README) + config (window_mode) + bump 0.3.0 → 0.4.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
* fix(stt): détection navigateur cross-distro (AlmaLinux/Fedora + Debian/Ubuntu)
_open_browser tente les binaires natifs (rpm + deb : brave-browser / chromium /
chromium-browser / google-chrome…) puis Flatpak (com.brave.Browser,
org.chromium.Chromium, com.google.Chrome…), sinon repli sur le navigateur par
défaut. systemd --user, lanceurs .desktop et pipx sont déjà identiques sur les
deux familles.
Doc : note de compatibilité distros. Bump 0.4.0 → 0.4.1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
* docs(stt): journal 2026-06-18 + PROGRESS + ligne STT du CLAUDE.md
- progress/2026-06-18.md : HUD avancé, auto-start, app de bureau, auto-update, cross-distro
- PROGRESS.md : entrée du jour
- CLAUDE.md : ligne STT enrichie (HUD, auto-start, app de bureau, auto-update)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
* feat(stt): fenêtre app autonome (profil + WM class dédiés, hors session Brave)
Le mode app s'attachait à la session Brave de l'utilisateur (même profil/icône) →
« ça sent le Brave ». On lance désormais une instance séparée : --class=STT-Funk
+ --user-data-dir dédié (~/.local/share/stt/app-profile), et le .desktop déclare
StartupWMClass=STT-Funk → fenêtre autonome avec sa propre icône de barre des tâches.
(Flatpak : --class seul, sandbox.) Une vraie fenêtre native (pywebview) reste une
option ultérieure. Bump 0.4.1 → 0.4.2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(stt): HUD avancé — design Claude Design câblé au backend
Remplace le HUD minimal (cercle CSS) par le design Claude Design : avatar
portrait réactif (anneau + ping d'écoute + spinner de réflexion), transcript
à bulles (tag modèle), indicateur de connexion + reconnexion auto, et un
drawer Réglages.
- HUD (stt/hud/index.html) : HTML/CSS/JS sans dépendance externe, DEMO=false
branché sur le websocket existant (états idle/listening/thinking/speaking,
user/assistant/error). Portraits chargés depuis hud/avatars/ (repli « あ »
si absent — voir avatars/README.md).
- Backend (ui/app.py) : le HUD renvoie {"type":"settings",...} ; le serveur
applique à chaud reset / mode cerveau (modèle LiteLLM) / mot de réveil via
_apply_settings (best-effort, non bloquant).
- engine/cli : tag du modèle courant ajouté aux réponses (events assistant).
- Docs : hud/README + avatars/README + admin/ia/stt.md (phase 4 ✅) + config.
Phase 4 de la roadmap STT. Reste : test sur poste + portraits réels.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
* fix(stt): HUD servi sans cache navigateur (anti ancienne version)
Le HUD est un dashboard live servi en statique : sans en-tête anti-cache, le
navigateur garde l'ancien index.html après mise à jour (« je vois encore la
version bleue »). Ajoute Cache-Control: no-store + Pragma: no-cache via un
handler dédié, et silence le log HTTP par requête.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
* chore(stt): bump client 0.1.0 → 0.2.0 (HUD avancé)
La version inchangée faisait que pipx/uv réutilisait l'ancien build en cache
lors d'un réinstall (HUD bleu persistant malgré le nouveau code). Le bump force
une résolution propre vers la nouvelle version (HUD design Claude Design).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
* fix(stt): cache-bust de l'URL HUD en kiosk + bump 0.2.1
Ouvre le HUD avec ?v=<timestamp> (URL unique par lancement) pour que le
navigateur ne puisse jamais servir une version cachée de l'ancien HUD.
Complète Cache-Control: no-store côté serveur.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
---------
Co-authored-by: Claude <noreply@anthropic.com>
Aligne la documentation sur l'état réel du cluster au 2026-06-18 :
- Qdrant : crash-loop résolu le 17/06 (statut « HS / EN COURS » corrigé dans
CLAUDE.md, README, admin/ia/rag.md, admin/incidents.md, admin/ia/stt.md).
Précision : collection funk-docs supprimée lors de la réparation → re-ingest
RAG encore à faire (pas de surévaluation du statut).
- STT (assistant vocal « Jarvis ») : ajouté partout (était déployé mais non documenté).
- Ghostfolio : ajouté partout (était déployé mais non documenté).
- Embeddings dédiés nomic-embed-text :1238 : marqués opérationnels (roadmap
README disait encore « TODO »).
- llama-server : ×3 → ×4 (instance embeddings) ; gap IaC précisé (embeddings géré
par le rôle, seules les 2 instances CPU restent manuelles).
- Structure k8s/ corrigée dans CLAUDE.md : ajout stt/ + ghostfolio/, suppression
des sous-dossiers traefik/ + metallb/ inexistants (installés via helm au bootstrap).
- Namespaces et liste des secrets Vault (vault_pg_ghostfolio_password) complétés.
- admin/README.md : index complété (~10 docs manquants : email, n8n, open-webui,
ghostfolio, k9s, stt, rag, hermes-voice/souls/auto-improve, alertmanager-webhook).
- Funk/ (conception d'origine : LM Studio + agents Goose, obsolète) déplacé sous
archive/ avec bandeau « obsolète » + archive/README.md (historique git préservé).
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
Co-authored-by: Claude <noreply@anthropic.com>
* feat(stt): mémoire long-terme sémantique via Qdrant (5b)
Serveur : longterm.py — collection Qdrant stt-memory (embeddings Qwen3 gpu-01, dim auto,
Cosine), recall top-k injecté au prompt, remember des tours user. Tout dégrade proprement
si Qdrant/embeddings injoignables (la mémoire court-terme tient). Env STT_MEMORY_LONGTERM,
STT_QDRANT_URL, STT_EMBED_URL, STT_MEMORY_TOPK.
Testé en process : dégradation OK (Qdrant down → mem=0, pas de crash, court-terme tient).
Qdrant réparé le 17/06 (5c). Recherche sémantique réelle à valider sur cluster.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
* feat(stt): endpoint /v1/memory/health + upsert Qdrant synchrone
- /v1/memory/health sonde activement embeddings + Qdrant + collection et
expose les erreurs (recall/remember dégradent en silence → indébogables).
Permet de diagnostiquer la mémoire long-terme sans kubectl exec.
- remember() : upsert avec ?wait=true → le souvenir est immédiatement
cherchable (sans wait, Qdrant met l'écriture en file → un recall
cross-session immédiat pouvait le rater).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
* docs(stt): 5b mémoire long-terme validée en prod + backlog nomic-embed-text
- Rappel cross-session confirmé (« Felix » retrouvé dans une nouvelle session),
points_count vérifié via /v1/memory/health.
- Note du fix upsert ?wait=true et de l'endpoint de diagnostic.
- Roadmap : 5d (nomic-embed-text dim 768) en backlog qualité ; états haut/bas
du doc mis à jour (déployé + validé sur cible).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
* feat(stt): embeddings dédiés nomic-embed-text sur gpu-01 (:1238) + migration auto
Remplace Qwen3 (chat réutilisé, dim 4096, peu discriminant) par un modèle
d'embedding spécialisé nomic-embed-text (dim 768) pour la mémoire long-terme.
Ansible (rôle llama_server) :
- nouvelle instance optionnelle `llama-embed` (llama_embed_enabled) servant un
modèle d'embedding dédié sur :1238, GPU ; télécharge le GGUF si absent.
- activée sur gpu-01 (host_vars) : nomic-embed-text-v1.5 f16.
STT-server :
- STT_EMBED_URL → :1238, STT_EMBED_MODEL → nomic-embed-text (deployment + config).
- _ensure_collection détecte le changement de dimension (4096→768) et recrée
automatiquement la collection stt-memory (anciens vecteurs incomparables) —
pas de drop manuel.
Docs : llama_server README, rag.md, stt.md (5d ✅), CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
* fix(stt): désactiver le mode thinking de Qwen3 (/no_think) — content vide / 502
Qwen3 est un modèle « thinking » : il dépensait tout le budget max_tokens en
reasoning_content → content vide, ou partait en raisonnement long → timeout (502
"upstream LiteLLM : " avec message vide). Diagnostic : appel direct LiteLLM en
0.87s mais content="" et tout dans reasoning_content.
- brain.py : ajoute le token de contrôle `/no_think` au system prompt
(configurable STT_DISABLE_THINKING, défaut true ; inoffensif pour non-Qwen).
- brain.py : filet de sécurité — si content vide, récupère reasoning_content
au lieu de renvoyer "".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
* docs(stt): documenter le fix /no_think Qwen3 + instance embeddings :1238
- admin/ia/stt.md : caveat « thinking » Qwen3 (content vide / timeout 502) +
fix /no_think + fallback reasoning_content ; roadmap 5e ; bannière.
- stt/server/README.md : env STT_DISABLE_THINKING + section caveat Qwen3.
- admin/ia/llama_server.md : 4e instance llama-embed :1238 (nomic, dim 768),
double source d'embeddings (1234 Qwen3 / 1238 nomic), caveat thinking,
correction dim Qwen3 (3584 → 4096).
- admin/ia/litellm.md : cross-ref caveat thinking (concerne tous les
consommateurs de hermes-default/qwen3).
- ci : exclure **/*.md du trigger build-stt-server (doc-only ne rebuild plus).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(stt): mémoire long-terme sémantique via Qdrant (5b)
Serveur : longterm.py — collection Qdrant stt-memory (embeddings Qwen3 gpu-01, dim auto,
Cosine), recall top-k injecté au prompt, remember des tours user. Tout dégrade proprement
si Qdrant/embeddings injoignables (la mémoire court-terme tient). Env STT_MEMORY_LONGTERM,
STT_QDRANT_URL, STT_EMBED_URL, STT_MEMORY_TOPK.
Testé en process : dégradation OK (Qdrant down → mem=0, pas de crash, court-terme tient).
Qdrant réparé le 17/06 (5c). Recherche sémantique réelle à valider sur cluster.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
* feat(stt): endpoint /v1/memory/health + upsert Qdrant synchrone
- /v1/memory/health sonde activement embeddings + Qdrant + collection et
expose les erreurs (recall/remember dégradent en silence → indébogables).
Permet de diagnostiquer la mémoire long-terme sans kubectl exec.
- remember() : upsert avec ?wait=true → le souvenir est immédiatement
cherchable (sans wait, Qdrant met l'écriture en file → un recall
cross-session immédiat pouvait le rater).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
* docs(stt): 5b mémoire long-terme validée en prod + backlog nomic-embed-text
- Rappel cross-session confirmé (« Felix » retrouvé dans une nouvelle session),
points_count vérifié via /v1/memory/health.
- Note du fix upsert ?wait=true et de l'endpoint de diagnostic.
- Roadmap : 5d (nomic-embed-text dim 768) en backlog qualité ; états haut/bas
du doc mis à jour (déployé + validé sur cible).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
* feat(stt): embeddings dédiés nomic-embed-text sur gpu-01 (:1238) + migration auto
Remplace Qwen3 (chat réutilisé, dim 4096, peu discriminant) par un modèle
d'embedding spécialisé nomic-embed-text (dim 768) pour la mémoire long-terme.
Ansible (rôle llama_server) :
- nouvelle instance optionnelle `llama-embed` (llama_embed_enabled) servant un
modèle d'embedding dédié sur :1238, GPU ; télécharge le GGUF si absent.
- activée sur gpu-01 (host_vars) : nomic-embed-text-v1.5 f16.
STT-server :
- STT_EMBED_URL → :1238, STT_EMBED_MODEL → nomic-embed-text (deployment + config).
- _ensure_collection détecte le changement de dimension (4096→768) et recrée
automatiquement la collection stt-memory (anciens vecteurs incomparables) —
pas de drop manuel.
Docs : llama_server README, rag.md, stt.md (5d ✅), CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
---------
Co-authored-by: Claude <noreply@anthropic.com>
Serveur : longterm.py — collection Qdrant stt-memory (embeddings Qwen3 gpu-01, dim auto,
Cosine), recall top-k injecté au prompt, remember des tours user. Tout dégrade proprement
si Qdrant/embeddings injoignables (la mémoire court-terme tient). Env STT_MEMORY_LONGTERM,
STT_QDRANT_URL, STT_EMBED_URL, STT_MEMORY_TOPK.
Testé en process : dégradation OK (Qdrant down → mem=0, pas de crash, court-terme tient).
Qdrant réparé le 17/06 (5c). Recherche sémantique réelle à valider sur cluster.
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
Co-authored-by: Claude <noreply@anthropic.com>
Serveur : SessionStore (historique borné + TTL, en mémoire), /v1/ask accepte session_id
et injecte l'historique dans l'appel LLM, /v1/reset l'efface. Dockerfile en 1 worker
(cohérence mémoire process).
Client : session_id généré par run (uuid), envoyé à chaque requête ; commande /reset
en mode texte.
Testé en process (TestClient) : historique croît 0→2→4, reset→0, sessions isolées,
sans session_id = sans état.
Mémoire long-terme Qdrant (5b) + réparation Qdrant (5c) à suivre.
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
Co-authored-by: Claude <noreply@anthropic.com>
Serveur : /v1/ask accepte un model optionnel (validé contre STT_ALLOWED_MODELS),
nouvel endpoint GET /v1/models (défaut + alias autorisés). Pas de switch global.
Client : 'stt --text' (chat texte simple sans micro/HUD), '--model hermes|claude|qwen|opus'
(noms courts → alias LiteLLM), commandes /model et /models en mode texte. Le modèle
choisi est envoyé au serveur à chaque requête (voix comme texte).
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
Co-authored-by: Claude <noreply@anthropic.com>
L'indirection litellm-ext (Service sans sélecteur + Endpoints manuel) ne routait pas
('All connection attempts failed'). open-webui joint LiteLLM en IP directe — on copie
ce pattern éprouvé et on supprime litellm-external.yaml.
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
Co-authored-by: Claude <noreply@anthropic.com>
Auth via jeton de securite (auto-renouvelle, plus d'expiration JWT). News par
action via Yahoo RSS dans le noeud Code. Analyse approfondie + recommandations.
Caveat: Qwen 8B peut se tromper sur les chiffres -> se fier au tableau exact.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cron dimanche 18h -> API Ghostfolio (perf+holdings) -> Qwen commente -> email.
Filtre le cash, poids relatifs aux actions. Auth JWT en dur (exp 2026-12-12).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le noeud Format Alertes lisait body.alerts/body.status au lieu de body.body.* ->
tous les mails affichaient 0 alerte/unknown meme en cas de vraie alerte.
Correctif applique au workflow (live) + filtre Watchdog/InfoInhibitor/severity none.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>