Skip to main content

agentmux_srv/server/app_api/
voice.rs

1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3
4//! `voice.checkPath` — live existence check for the local whisper.cpp CLI
5//! binary or GGML model file paths configured in Settings -> Recording.
6//!
7//! Exposes the exact same `Path::new(&p).exists()` check
8//! `crates/srv/src/server/voice.rs` already performs inline at actual
9//! transcription time (`voice.rs`'s `transcribe_local_whisper` /
10//! `ensure_local_model`) -- no new validation logic, just surfacing it
11//! proactively so the Settings UI can show live status instead of only
12//! failing at first-recording-attempt. See
13//! docs/specs/SPEC_SETTINGS_RECORDING_INPUT_SECTION_2026_08_19.md §3.
14
15use super::*;
16
17pub fn register(engine: &Arc<WshRpcEngine>, _state: &AppState) {
18    register_voice_check_path(engine);
19}
20
21fn register_voice_check_path(engine: &Arc<WshRpcEngine>) {
22    // Typed registration (SPEC_RPC_BINDINGS_CODEGEN_2026_09_07.md §3.1): the
23    // request/response structs are named in `rpc_types` and carry
24    // `#[derive(ts_rs::TS)]`, so `frontend/types/rpc/` gets them generated
25    // and `scripts/check-rpc-bindings.sh` fails the build if the two sides
26    // drift. Replaces a private `VoiceCheckPathReq` + an anonymous
27    // `json!({"exists": ..})`, neither of which the generator could see.
28    engine.register_typed(
29        COMMAND_VOICE_CHECK_PATH,
30        move |req: CommandVoiceCheckPathData, _ctx| async move {
31            let trimmed = req.path.trim();
32            let exists = !trimmed.is_empty() && std::path::Path::new(trimmed).exists();
33            Ok(VoiceCheckPathResult { exists })
34        },
35    );
36}