ROOT CAUSE ANALYSIS
User reported: (a) TTS dropdown doesn't apply, (b) GUI feels stretched,
(c) no link to command builder, (d) Python doesn't even start.
Issues (a), (b), (c) addressed here. (d) addressed in python repo.
=== Fix A: TTS hot-swap (was completely broken) ===
Two distinct bugs:
1. `tts::init_backend()` only read JARVIS_TTS env var, NEVER consulted
`Settings.tts_backend` in the DB. So saving "Silero" in the GUI
dropdown changed nothing — not even on restart.
2. `BACKEND: OnceCell<...>` couldn't be replaced at runtime, so even
if init had picked the right backend, the dropdown was useless
mid-session.
Fixed:
- `tts::BACKEND` is now `Lazy<RwLock<Option<Arc<dyn TtsBackend>>>>`.
- `choose_backend_name()` resolves from DB → env → auto-detect.
- New `swap_to(name)` replaces the live backend atomically.
- IPC: new `IpcAction::SwitchTts { backend }`. jarvis-app reacts to
it the same way it reacts to SwitchLlm.
- GUI's `set_tts_backend` now persists + hot-swaps GUI's TTS + Svelte
page also fires `switchDaemonTts()` over WS so the running daemon
installs the new backend.
- Removed "Применится при следующем запуске" hint — now applies
immediately. RU + EN locale strings updated.
=== Fix B: GUI max-width ===
main + #header had no max-width, so on a 1920px monitor the labels
sprawled across 1860px of space, which felt stretched. Added
max-width: 1280px + margin: 0 auto + box-sizing: border-box. Smaller
windows are unaffected.
Also added the same cap on .app-container.assist-page so the home
screen arc reactor centres properly.
=== Fix C: Command builder discoverable ===
The Python fork ships a separate yaml-editing tool at
`python/tools/command_builder/` (pywebview GUI). No way to find it
from the main Rust GUI. Fixed:
- New tauri command `open_command_builder` (crates/jarvis-gui/src/
tauri_commands/builder.rs). Locates the Python fork via
$JARVIS_PYTHON_DIR → sibling python/ → C:\Jarvis\python, prefers
the project's .venv, spawns `python -m tools.command_builder`.
- New blue "Конструктор команд (Python)" button on /settings page
near the Save / Back buttons.
Tests: 140 rust + 104 python all pass. Release builds of jarvis-app
and jarvis-gui both green.
CI (.github/workflows/ci.yml):
- Three parallel jobs on push & PR: cargo test (jarvis-core), cargo
clippy (lint, warnings-as-errors), cargo check (workspace). Windows
runner, stable toolchain, rust-cache for fast incremental builds.
- Deliberately skips release build of jarvis-gui — that needs Node+npm
+Tauri bundler and would balloon CI to ~10min per push.
Drop Ukrainian:
- Delete ua.ftl, remove UA from SUPPORTED_LANGUAGES.
- config.rs: prune UA arms from get_wake_phrases / get_wake_grammar /
get_phrases_to_remove / get_llm_trigger_phrases / get_llm_system_prompt.
- stt/vosk.rs: drop UA → uk language mapping.
- tray menu: drop "Українська" entry.
- frontend: drop UA from Header.svelte language list, settings page
language map, i18n.ts fallback.
- 82 command.toml files stripped of every `ua = [...]` block (205
blocks total). Handled via subagent — TOML still parses, all 6 command
tests pass.
.gitignore: stop tracking dev.env / dll_probe*.py / imports_full.txt
which were sitting in working tree.
Tests: 128 pass (no regression). Workspace still compiles end-to-end.
a6a098d added daemon-side IPC handlers (SwitchLlm, ReloadLlm, QueryHealth)
but the GUI was still talking only to its own process. This commit wires
the frontend to actually use those handlers.
frontend/src/lib/ipc.ts
- New DaemonHealth interface + daemonHealth: writable<DaemonHealth | null>.
- handleEvent: "health_snapshot" case fills daemonHealth from daemon's IpcEvent.
- New senders:
switchDaemonLlm(backend) → action "switch_llm"
reloadDaemonLlm() → action "reload_llm"
queryDaemonHealth() → action "query_health"
frontend/src/stores.ts
- Re-exports daemonHealth + the three new senders + DaemonHealth type.
frontend/src/components/Footer.svelte
- Polls every 5s but PREFERS IPC: if daemon connected, calls queryDaemonHealth
(snapshot arrives via daemonHealth store).
- Falls back to invoke("get_active_backends") if daemon offline — shows
GUI-process view in that case, with the chip tooltip distinguishing
"daemon" vs "gui-process" source.
frontend/src/routes/settings/index.svelte (AI Backends tab)
- applyLlmBackend now ALSO fires switchDaemonLlm so the running listener
picks the new backend without restart.
- "Auto" (empty) path calls reloadDaemonLlm so daemon re-reads DB.
End-to-end flow now:
GUI dropdown → set_llm_backend (Tauri, persists DB + swaps GUI proc)
↘ switchDaemonLlm (IPC, swaps daemon proc too)
↘ daemon emits health_snapshot on next QueryHealth
↘ daemonHealth store updates
↘ Footer chips re-render with new state
Build: cargo build --release -p jarvis-gui green.
Surfaces the LLM/TTS hot-swap UX in the GUI so the user doesn't need env vars
or voice commands. Tauri commands for this landed in b243e67; this commit
wires them to Svelte.
Footer (frontend/src/components/Footer.svelte)
- Poll get_active_backends() every 5 s, show TTS / LLM / Profile chips.
- Chips have border accents by kind (cyan = TTS, lime = LLM, orange = Profile).
- Friendly title tooltips with full backend + model names.
- Silent if jarvis-gui can't reach the command (e.g. cold start) — no UI flicker.
Settings — new "AI Backends" tab (frontend/src/routes/settings/index.svelte)
- Status banner showing active LLM (with model name) + TTS + Profile.
- LLM selector: Auto / Groq / Ollama → calls set_llm_backend on change
(hot-swap, persisted to DB).
- TTS selector: Auto / SAPI / Piper / Silero → calls set_tts_backend
(persisted, effective on next jarvis-app restart).
- "Reset context" button → llm_reset_context Tauri command.
- Error toast for swap failures (e.g. Groq selected but no GROQ_TOKEN).
- Tips alert: how to install Ollama / Piper / voice commands.
- Loads prefs via db_read('llm_backend' / 'tts_backend') on mount.
i18n strings (ru/en/ua, .ftl files)
- 14 new keys: settings-ai-backends, settings-ai-active, settings-ai-auto,
settings-ai-applying, settings-ai-error, settings-ai-tips,
settings-llm-backend{,-desc}, settings-tts-backend{,-desc},
settings-llm-context{,-desc}, settings-llm-reset, settings-profile.
Build glue (crates/jarvis-gui/Cargo.toml)
- jarvis-core dep now includes the `llm` feature so backends.rs can resolve
`jarvis_core::llm::*` (was failing to compile after the global LLM module).
.gitignore
- tools/piper/*.dll, piper.exe, voices/, espeak-ng-data/ — locally
installed binaries from tools/piper/install.ps1, not committed.
Build: cargo build --release -p jarvis-gui green (4m, includes npm/Vite).
Test path: rebuild + launch jarvis-gui, /settings → "AI Backends" tab.