Aller au contenu

Changelog - Lyra

[Unreleased]

[1.4.0] - 2026-11-06

Breaking

  • scripts/async_mcp_wrapper.py no longer falls back to ~/dev/fedora-setup/scripts: background MCP scripts are resolved only from the root-owned copy (/usr/local/lib/lyra/scripts, LYRA_SCRIPTS_DIR or paths.scripts). The old path was user-writable and covered by no sudoers rule; run the installer (or set LYRA_SCRIPTS_DIR) if you relied on it.

Added

  • Releases: sbom.json (CycloneDX inventory of the base and gpu dependencies, exact versions from uv.lock) attached to each GitHub release; wheel and sdist carry a SLSA provenance attestation and an SBOM attestation, both verifiable with gh attestation verify. The release refuses to build when uv.lock is stale. Procedure in docs/dev/release-process.md.

Security

  • Background tasks: their .log, .pid, .progress and .done files move from /tmp (predictable names, readable by every account) to a private 0700 directory, $XDG_RUNTIME_DIR/lyra/tasks (LYRA_TASK_DIR to override). The Discord webhook reaches the task wrapper through the environment, no longer as a command-line argument visible to every account in the process list.
  • Daemon socket: created with mode 0600 directly (umask around bind) instead of being chmod-ed right after, and ~/.lyra is created 0700.
  • The MCP destructiveHint annotation now requires a strict confirmation in the daemon and in standalone mode, like DANGEROUS_TOOLS. A third-party server that marked a tool destructive only got the soft [O/n] prompt (Enter = yes), and -y ran it without asking: the annotation was read by Pipeline.is_dangerous_action, which nothing called. Bundled servers are unaffected (fedora-agents annotates exactly the tools already listed).
  • Graphical installer (install.sh --app, 127.0.0.1:9877): a web page open in the browser could start the install and answer its confirmations (no Host, Origin or Content-Type check; a text/plain POST needs no CORS preflight; question ids were ask-1, ask-2...), and options.ollama_host was written unquoted into ~/.bashrc, so a crafted value ran shell code at the next login. The backend now refuses a non-local Host (DNS rebinding), a foreign Origin and any non-JSON POST; question ids are random; ollama_host must be a host name or an IP (all frontends: app, TUI, headless) and is quoted in .bashrc.

Changed

  • CI: ruff lint is now blocking (240 findings cleared: 139 were the documented from manim import * of the intro animations, now a per-file ignore; main.py keeps its CUDA-before-imports order under a justified E402 ignore). The test job also runs scenes/ironman.

Fixed

  • Discord notifications: the webhook is read from config.yaml, then from the neighbouring secrets.yaml where config.yaml.example and the data-flow doc put it; only config.yaml was read, so a webhook stored as documented sent nothing (daemon and standalone mode).
  • scripts/async_mcp_wrapper.py ran sudo -n on scripts under ~/dev/fedora-setup/scripts: no sudoers rule covers that user-writable path, so system clone, backup creation and backup restore failed when run in the background. It now uses the root-owned copy resolved by lyra.core.paths (/usr/local/lib/lyra/scripts, LYRA_SCRIPTS_DIR, paths.scripts).
  • main_rag.py: the module docstring sat after from __future__ import annotations, so it was not the docstring (and flagged every import); it is first again.
  • Bare except: in ephaistos and the MCP client no longer swallow Ctrl+C.
  • Tests: the Iron Man red-flash test now checks the colour sent to the lamp (it computed it without asserting); the phase 0 timing test mocks the parallel state reads added with the refactor (it made real requests and measured their 2 s timeout).
  • Dead code removed: an unused Zod pattern in the indexer, an unused score colour in the step display.

[1.3.1] - 2026-09-24

Added

  • Daemon: tool message on the socket for clients that only need one MCP call (name, arguments, confirmed option). The daemon checks the HESTIA catalogue, asks for confirmation when the tool is dangerous and not confirmed, runs it under the busy lock and streams tool_result then result. No model in the loop; used by neutroncore (roadmap issue 73).

Changed

  • MCP_TOOLS.md regenerated: tv.get_state now reports volume, mute and ambilight; denon.get_status reports mute, source and reachability (pylips-mcp 0.2.0, denon-mcp 0.2.0).
  • First release built and published by the shared release workflow (PyPI Trusted Publishing); 1.3.0 was tagged before the workflow existed.

[1.3.0] - 2026-09-24

Added

  • lyra --version prints the installed lyra-assistant version, or the pyproject version when run from sources (#15).
  • scripts/gen_mcp_tools_md.py regenerates docs/user/MCP_TOOLS.md from the live MCP servers, with a confirmation column derived from lyra/core/constants.py.
  • EPHAISTOS variants inventaire_vm (real VM names from vm_status or LYRA_VMS), lexique_courant and verbes_courants (everyday French synonyms and verbs, written outside any test set).
  • Fourth held-out set tests/cases_hors_regles_3.py (50 phrasings, real machine names, ten tools never measured before); fifth set tests/cases_hors_regles_4.py, sealed before iteration 16.
  • scripts/bench_recall.py: mechanical recall of a set (rank of the expected tool, precision of the "net" criterion) without calling the model, the measurement to run before any bench.
  • EPHAISTOS variants outil_par_machine, mots_courants_2, nombres_tri, mots_courants_3 (iterations 15-16); net_assoupli measured and refuted.
  • Iterations 17-21 ("99 % on every set"): variants cartes_17, lumiere_sans_verbe, nom_de_vm (replayed), force_definitif; the five development sets reach 21/21, 51/51, 100/100, 50/50, 50/50 with qwen2.5-coder:0.5b; a sixth set (tests/cases_hors_regles_5.py) sealed first and measured once.

Changed

  • EPHAISTOS: the 17 refuted or neutral variants are removed from the code (module 1581 -> ~810 lines); the 42 retained ones are the default configuration, still switchable one by one through LYRA_EXP for ablation. Word tables and lexicons move to lyra/models/cartes.py (data only). Mechanical recall and the benches are identical before and after (21/21, 51/51, 100/100).
  • docs/articles/2026-09-boucle-ephaistos.fr.md: the improvement loop written up as a research report (abstract, method, results, limits, reproduction), with five SVG figures generated from benchmarks/results/ by scripts/gen_figures_boucle.py.

Fixed

  • The daemon did not run the path the bench measured. EnhancedPipeline sent EPHAISTOS a single spec, without the tool_name: prefix, then let a session-context injection and the intent classifier override the result: "reveille fedora-base" gave tv.power_on, "archive test-vm" gave tv.mute, "de la lumiere dans le salon" was answered as small talk (manual acceptance test, 2026-09-23). The pipeline now builds the specs exactly like the bench (specs_pour_ephaistos, shared), passes all of them, skips the context injection when the variants are active, and treats a query as a command when the spec sort is unambiguous (Ephaistos.est_net). tests/test_campaign_llm.py --reel measures this real path (one session per case, correct refusals of unknown VMs counted apart): 21/21, 43/43 and 91/92 on the three development sets.
  • One-shot calls: a pending clarification or choice left in the shared session polluted the next call ("mets staging-03 au repos" was read as an answer about preprod-10). It is cleared when nobody can answer.
  • Argument names invented by the 0.5b in missing_args ("chromecast") no longer trigger a clarification; only real parameters of the tool count.
  • Hue: a group_id that does not exist on the bridge is replaced by the default group (real groups read at startup).
  • Performance mode (-p) and -y: LYRA printed "Tu confirmes ?" then executed without waiting; it now says what it does.
  • Slang normalizer: URLs are no longer lowercased (a YouTube id is case-sensitive).
  • A matching rule, or a spec sort that recognises a tool word, is a command whatever the intent classifier says ("silence sur l'ampli" and "les leds de la tele, tu me les enleves" got no action); a tool imposed by a net sort no longer triggers the disambiguation question.
  • Rules: "affiche les taches" lists the running tasks; the Denon rule also answers to "ampli", "AVR" and "home cinema" ("l'ampli sur game"), a state question gives get_status, "bascule ... sur le bluray" is a source change.
  • Security: main_rag.py compared a prefixed tool name (fedora.vm_destroy) to the short names of DANGEROUS_TOOLS, so -y skipped the confirmation of destructive tools; it now uses is_dangerous_tool().
  • Security: an empty answer (Enter) no longer confirms a sensitive or destructive action in the daemon UI and the terminal UI; o/oui is required, as in actions.py.
  • Security: vm_snapshot (revert/delete), vm_import and vm_copy are now in DANGEROUS_TOOLS; PERFORMANCE_TOOLS entries are prefixed (the eight cast_* never matched), Denon and read-only tools added; main.py (legacy) no longer keeps its own diverging lists.
  • Rules: tv.sound_only and tv.ambilight_color do not exist in pylips-mcp; "son seul / mode musique" now maps to tv.screen_off, a colour request to ambilight_mode(manual) (pylips-mcp#7); tv.youtube_video sends video (schema name) instead of video_id.
  • Rules: "lance CMD sur VM" is an exec, "l'etat de la lampe" is not a VM status, "il est tard" is not a state question (found by the fourth set control).
  • scripts/index_rag_3tier.py ignores documents without server_name (a local ironman.run_scene would have created an UNKNOWN server); config.yaml.example declares the catt server.
  • EPHAISTOS: a tool imposed by a net sort was overridden by the second pass (double_passe) and applied after the argument completion; the net criterion ignored the machine bonus. Three fixes with unit tests.
  • Rules: "eteins les leds de la tele" was a power_off (sixth set control).
  • Config: the dead security.destructive_tools list (never read, listed a non-existent vm_delete) is removed from config.yaml.example; lyra/core/constants.py is the only source. docs/dev/INDEX_RAG.md documents the v2 -> v3 regeneration order.
  • Rules: the screen-manager module is out of the registry (server absent from disk and config, lyra#24); a room name is not a VM; "arrete la synchro des lampes" is not a task kill; a question about the chromecast is cast_status; "l'ambilight qui suit la musique" sets the mode. tracking.delete and tracking.kill_task require an explicit confirmation.

[1.2.0] - 2026-09-10

Added

  • docs/user/DATA_FLOWS.md: what Lyra captures, keeps, and the optional network outputs with their switches.
  • VOICES.md and docs/licenses/: Piper voice licences, Llama 3.2 Community License and use policy ("Built with Llama").
  • THIRD_PARTY_LICENSES.md generated by make licenses and checked in CI.
  • README: English summary, prerequisites table, security guarantees mapped to code and tests, clickable metrics, ecosystem block.
  • ROADMAP.md.

Changed

  • Packaging: hatchling, distribution name lyra-assistant, dependencies in pyproject with gpu/dev extras and a uv lockfile; CUDA libraries are no longer imposed.
  • CI: reusable workflow (unit + installer tests on 3.11/3.12, ruff, personal-path guard), Dependabot.
  • systemd units shipped with @LYRA_DIR@ / @HOME@ placeholders; no personal path left in code, scripts or tests.
  • Tracking client defaults come from TRACKING_SERVER_SCRIPT / TRACKING_VENV_PYTHON; RAG spec sources from LYRA_MCP_SPECS_DIR.

[1.1.0] - 2026-09-09

Changed

  • License: AGPL-3.0-or-later with a commercial license option and a CLA (versions up to 1.0.0 remain MIT).
  • README: HTTPS clone URL, status badges, dated claims, no more reference to a web domain.
  • CLAUDE.md condensed to what an agent needs.

Removed

  • Generated artifacts (empty ChromaDB databases, test reports, Manim caches), the self-referencing lyra/run.sh symlink that broke CI, and workshop files (Claude Code prompts, session notes, n8n exports, divergent documentation copy), now archived privately.

Fixed

  • CI: the pip cache step no longer fails on a symlink loop.

[v1.1.0 - Pipeline modulaire complet] - 2026-03-10

Refactoring - Decomposition de pipeline.py en modules separes (7 missions)

pipeline.py passe de 2899 lignes a 919 lignes (~68% de reduction). 164/164 tests MCP conserves a 100% apres chaque mission.

Mission 1 - Types et constantes (core/types.py, core/config.py) - Extraction de QueryType, PipelineResult, constantes MCP (CATEGORY_KEYWORDS, TOOL_TYPE_KEYWORDS, etc.)

Mission 2 - Retrievers (core/retrieval.py) - Classe Retriever : encapsule SemanticRetriever + KeywordRetriever + RRFFusion - API : initialize(), retrieve(query), detect_query_type(query) - Pipeline utilise self._retriever au lieu de 3 composants separes

Mission 3 - Menus outils (core/menus.py) - is_list_tools_query(), process_tools_query_step1(), handle_server_selection() - Constantes LIST_VERBS, LIST_SUBJECTS

Mission 4 - Workflows base (core/workflows/) - context.py : WorkflowContext avec callables injectes (prepare_execution, route_query) - vm_start.py : handle_vm_start_confirm() (4 cas oui/non/clarification/autre) - vm_stop.py : handle_vm_stop_choice() (choix 1/2/3 arret VM avant clone) - vm_snapshot.py : handle_vm_snapshot_create_workflow(), handle_vm_snapshot_list_workflow(), handle_vm_snapshot_pending()

Mission 5 - Workflows clone/export (core/workflows/vm_clone.py, vm_export.py) - vm_clone.py : suggest_vm_name(), handle_cow_choice(), handle_vm_clone_workflow() (6 cas validation) - vm_export.py : CUSTOM_EXPORT_GROUPS, workflow multi-tours (6 groupes virt-sysprep + firstboot)

Mission 6 - Formatters et validation (core/formatters.py, core/validation.py) - formatters.py : enrich_description(), enrich_optional_args(), format_listing_result() - validation.py : validate_vm_existence(), helpers VM state, constantes outils VM

Mission 7 - Cleanup final - Suppression imports inutilises (re, sys, unicodedata) dans pipeline.py - Mise a jour CLAUDE.md section "Project Structure" - 164/164 PASS confirme (100%)


[v0.7 - 53/54 Tests MCP] - 2026-02-25

Campagne de tests complete - 54 tests MCP one-shot

Passage de 38/54 (70%) a 53/54 (98%). Un seul FAIL attendu (T10: vm_clone, source VM inexistante).

Fixes FEDORA: - T1: vm_status({}) pour listing global (etait vm_name='' -> EXEC_ERROR) - T6: vm_exec(vm_name, cmd) "execute CMD sur VM" (etait ls() mauvais outil) - T7: vm_copy(source, vm_name, dest) "copie FILE vers VM" (etait FAIL) - T11: vm_clone_system(name) "clone systeme VM en NEWVM" (etait FAIL) - T12: vm_verify(vm_name) "verifie la VM NAME" (etait FAIL) - T14: backup_status({}) sans watch=True (etait TIMEOUT boucle infinie) - T15: backup_create(vm_name) args corrects (etait sans vm_name) - T16: backup_verify(vm_name) argument correct (etait type= au lieu de vm_name=)

Fixes TV: - T30: tv.volume_up (etait tv.power_on) - T31: tv.volume_down (etait FAIL) - T33: tv.mute (etait tv.power_off)

Fixes DENON: - T39: denon.power_off (etait eteins() mauvais outil) - T42: denon.volume_set(level=50) (etait hue.set_brightness mauvais outil!) - T44: denon.mute_off (etait denon(status=off))

Fixes HUE: - T19: hue.turn_on_group(group_id=81) (etait allume() via embedding ChromaDB confus) - T27: hue.turn_off_light (etait turn_on_light!)

Fixes CATT: - T46: catt.cast_scan (etait catt.cast_dual_stop) - T51: catt.cast_volume (etait denon.volume_up + intent=knowledge)

Changements techniques:

  1. BM25 accent normalization (keyword_retriever.py):
  2. _tokenize() normalise les accents (NFD) avant BM25
  3. "Demarre" dans docs ChromaDB = "demarre" dans query sans accent

  4. _rule_based_detect() etendue (pipeline.py):

  5. BACKUP (6 regles): backup_status/list/verify/create/restore/clean
  6. FEDORA VM (9 regles): vm_start/stop/destroy/exec/snapshot/status/verify/copy/clone_system
  7. CATT (2 regles): cast_scan, cast_volume (avec support "diffuse" = SlangNorm("cast"))
  8. HUE (2 regles): turn_on_group, turn_off_light
  9. vm_start: exclusion TV context ("lance Netflix sur la TV" -> PAS vm_start)

  10. _DEMANDE_VERBS_RE etendu (intent_classifier.py):

  11. Ajoute: status|statut|nettoie|restaure|allume|eteins|mute|scan|caste|lance|demarre|arrete|supprime

  12. FRENCH_ENRICHMENTS (pipeline.py):

  13. turn_on_group/turn_off_group: retire verbes dupliques (deja fournis par "turn_on"/"turn_off")
  14. Distingue singular ("lumiere") vs pluriel ("lumieres") pour light vs group

  15. Normalisation accents dans _rule_based_detect():

  16. NFD normalization au debut (SlangNorm ajoute des accents: "execute"->"exécute")

Fichiers modifies: - lyra/rag/keyword_retriever.py: _tokenize() accent normalization - lyra/models/intent_classifier.py: _DEMANDE_VERBS_RE etendu - lyra/core/pipeline.py: _rule_based_detect(), FRENCH_ENRICHMENTS, vm_start TV exclusion


[v0.6.1 - Fixes RAG TV/DENON/CATT] - 2026-02-25

Fixes RAG TV/DENON/CATT (pipeline.py)

Cause racine: EPHAISTOS 0.5b echoue sur les outils domotique (volume TV, mute, Denon). BM25 retourne de mauvais outils ("volume denon a 50" → catt.cast_volume, "demute le denon" → denon.power_off). SlangNormalizer transforme "cast" → "diffuse" ce qui casse la detection cast_scan.

Fix: regles TV/DENON/CATT dans _rule_based_detect() (pipeline.py): - TV: tv.volume_up/down/set/mute detectes par presence de "tv/tele" + verbe/chiffre/sourdine - DENON: denon.power_on/off/mute_on/off/volume_up/down/set detectes par presence de "denon" - Couvre formes original ("eteins", "demute") et normalisees ("sourdine") - Ordre: power_off/on → mute_off/on → volume_set → volume_up/down - CATT scan: "scan + cast/diffuse/appareils" → catt.cast_scan (gere les deux formes: original "cast" et SlangNorm "diffuse")

Resultats:

Query Avant Apres
"monte le volume de la TV" EPHAISTOS 0.5b echec tv.volume_up OK
"coupe le son de la TV" EPHAISTOS 0.5b echec tv.mute OK
"volume denon a 50" BM25 → catt.cast_volume denon.volume_set {level:50} OK
"demute le denon" BM25 → denon.power_off denon.mute_off OK
"eteins le denon" BM25 score trop bas denon.power_off OK
"scan les appareils cast" SlangNorm → cast_youtube catt.cast_scan OK

Fichiers modifies: - lyra/core/pipeline.py : _rule_based_detect() etendu avec regles TV/DENON/CATT


[v0.6 - One-Shot + Fixes RAG] - 2026-02-25

Mode One-Shot CLI

Ajout du mode one-shot: lyra "[requete]" [-v] [-y]

  • lyra "demarre preprod-01" - execution directe sans UI interactive
  • -v / --verbose : affiche les etapes RAG en temps reel ([rag], [intent], [action])
  • -y / --yes : auto-confirme les actions (mode non interactif)
  • Codes de sortie: 0=OK, 1=EXEC_ERROR, 2=CANCEL, 3=PIPELINE_FAIL, 124=TIMEOUT

Fichiers modifies: - main_rag.py : fonction run_one_shot(), argparse mis a jour - run.sh : documentation one-shot dans les commentaires

Tests MCP one-shot (54 tests)

Resultats: 38/54 = 70% (voir test_mcp_results.md)

Serveur Total OK Problemes
FEDORA 18 11 7
HUE 9 8 1
TV 9 5 4
DENON 9 6 3
CATT 8 7 1
MERMAID 1 1 0

Fixes RAG FEDORA (vm_clone_system, vm_clone, vm_copy, vm_verify)

Cause racine identifiee: EPHAISTOS 0.5b trop petit pour extraire les arguments, enrichissements BM25 confondent "copie" avec vm_clone, IntentClassifier classe "verifie" comme "info".

Fix 1 - vm_clone_system (pipeline.py): - Bug substring: "vm_clone" in "fedora.vm_clone_system" = True - Fix: analysis.tool in ("vm_clone", "fedora.vm_clone")

Fix 2 - vm_clone (pipeline.py): - EPHAISTOS detecte l'outil mais arguments={} + missing_args=[] → NullPointerError ligne 1290 - Fix: regex fallback dans _handle_vm_clone_workflow extrait "clone X en Y" - Fix: null-check if source_vm and vm.replace(...) - Fix: _rule_based_detect() intercepte "clone X en Y" avant EPHAISTOS

Fix 3 - vm_copy (pipeline.py): - BM25 retourne vm_clone au lieu de vm_copy ("copie" present dans enrichissement "clone") - Fix: _rule_based_detect() intercepte "copie/transfere FILE vers/sur VM"

Fix 4 - vm_verify (intent_classifier.py, pipeline.py): - IntentClassifier (Llama 1b) classe "verifie la VM" comme "info" → pipeline ignorait l'outil - Fix: regex override _DEMANDE_VERBS_RE dans classify() force "demande" pour verbes d'action - Fix: _rule_based_detect() intercepte "verifie/verif [la VM] NAME"

Nouveaux examples EPHAISTOS (ephaistos.py): - vm_clone avec source_vm + new_vm_name - vm_copy avec source + vm_name + dest - vm_verify avec vm_name optionnel - vm_clone_system avec name

Fichiers modifies: - lyra/core/pipeline.py : import re, _rule_based_detect(), fixes _handle_vm_clone_workflow - lyra/models/intent_classifier.py : _DEMANDE_VERBS_RE, exemples prompt - lyra/models/ephaistos.py : 4 nouveaux exemples FEDORA


[Phase 4] - 2026-01-23

Operations Async via n8n + Fallback Subprocess

Ajouts: - Module modules/n8n.py : Client n8n + executeur async fallback - 3 workflows n8n crees avec noeud code (JS) - Detection automatique des operations longues (vm_clone, backup_create, backup_restore) - Fallback subprocess : Si n8n non disponible, execute en arriere-plan via threading - Notification dans le terminal quand operation terminee (mode fallback)

Workflows n8n: | Workflow | Webhook | Description | |----------|---------|-------------| | Lyra - Clone VM v2 | /webhook/lyra-clone-vm-v2 | Clone VM via kvm-clone.sh | | Lyra - Backup Create | /webhook/lyra-backup-create | Cree backup timeshift/borg | | Lyra - Backup Restore | /webhook/lyra-backup-restore | Restaure backup |

Note: Les workflows utilisent le noeud n8n-nodes-base.code au lieu de executeCommand (ce dernier n'etait pas reconnu par l'API).

Fichiers modifies: - main.py : Integration n8n avec fallback subprocess - modules/n8n.py : Client n8n + AsyncExecutor pour fallback - config.yaml : n8n.enabled = true, webhook path mis a jour - prompts/system_prompt.txt : Section operations async

Mode fallback (subprocess): Quand n8n n'est pas disponible ou les webhooks ne sont pas actifs: 1. Lyra detecte l'echec du webhook 2. Lance la commande en arriere-plan via subprocess.Popen 3. Notifie dans le terminal quand c'est termine

Configuration requise:

n8n:
  enabled: true
  base_url: http://localhost:5678
  api_key: <votre-cle-api>  # Optionnel
  webhooks:
    clone-vm: /webhook/lyra-clone-vm-v2
    backup-create: /webhook/lyra-backup-create
    backup-restore: /webhook/lyra-backup-restore

Pour activer les webhooks n8n: 1. Aller sur http://localhost:5678 2. Ouvrir chaque workflow Lyra 3. Cliquer sur le toggle "Active" en haut a droite 4. Les webhooks seront alors operationnels


[Phase 3] - 2026-01-23

Actions + Securite

Ajouts: - Principe Read-First : verification automatique de l'etat VM avant toute action - System prompt externe (prompts/system_prompt.txt) au lieu de hardcode - Confirmation vocale avec mots-cles ("oui"/"non"/"oui je confirme") - Affichage de l'etat VM dans la confirmation (status, IP) - Description vocale naturelle des actions proposees

Regles de securite: - READ_FIRST_TOOLS : vm_start, vm_stop, vm_destroy, vm_snapshot, vm_clone - READ_ONLY_TOOLS : vm_status, backup_status, backup_list, backup_verify - Actions dangereuses : confirmation explicite "oui je confirme" en vocal

Fichiers modifies: - main.py : Chargement prompt externe, Read-First, descriptions vocales - modules/ui.py : Confirmation vocale, affichage etat VM - prompts/system_prompt.txt : Regles de securite detaillees

Confirmation vocale: - Option [v] pour passer en mode vocal - Mots-cles acceptes : oui, yes, ok, d'accord, confirme, vas-y - Mots-cles annulation : non, no, annule, stop, arrete - Actions destructives : exigent "oui je confirme"


[Phase 2] - 2026-01-22

Mode Vocal (STT/TTS)

Ajouts: - Mode --vocal pour interaction vocale complete - Module modules/audio.py : STT, TTS, AudioRecorder, VoiceInterface - Script run.sh : Lancement avec configuration CUDA automatique - Alias bash lyra et lyra --vocal - Bip sonore avant l'ecoute - Indicateur visuel de niveau audio en temps reel - Detection de silence pour fin d'enregistrement automatique

Stack vocale: - STT : faster-whisper (modele base, CUDA float16) - TTS : Piper (voix fr_FR-upmc-medium) - Audio : sounddevice avec resampling 48kHz

Configuration (config.yaml):

audio:
  sample_rate: 48000      # Compatible PipeWire/ALSA
  silence_threshold: 0.005
  silence_duration: 1.0
stt:
  model: base
  device: cuda
  compute_type: float16
tts:
  model: fr_FR-upmc-medium

Dependances ajoutees: - faster-whisper - piper-tts - sounddevice - nvidia-cublas-cu12 - nvidia-cudnn-cu12

Fixes techniques: - Resampling audio : 48kHz (PipeWire) <-> 16kHz (Whisper) <-> 22050Hz (Piper) - suppress_stderr() : Masque les warnings cffi de sounddevice - Configuration CUDA via LD_LIBRARY_PATH dans run.sh

Issue connue: - Elgato Wave 3 non fonctionnel (necessite Wave Link sur Windows/Mac) - Workaround : Utiliser G522 LIGHTSPEED comme micro par defaut


[Phase 1] - 2024

Wrapper Python + MCP (mode texte)

Fonctionnalites: - Client Ollama avec parsing JSON des tool calls - Client MCP pour fedora-agents - Human-in-the-Loop : confirmation avant execution - Interface CLI en francais - Raccourcis clavier (Ctrl+L, double Ctrl+C)

Outils MCP disponibles: - VM : vm_status, vm_start, vm_stop, vm_snapshot, vm_exec, vm_clone - Backup : backup_status, backup_list, backup_create, backup_verify