Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions crates/genie-core/src/voice_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ async fn run_with_wakeword(
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::null())
.kill_on_drop(true)
.spawn()
{
Ok(c) => c,
Expand All @@ -252,9 +253,24 @@ async fn run_with_wakeword(
let mut reader = BufReader::new(stdout);
let mut writer = stdin;

// Wait for "LISTENING" signal.
// Wait for "LISTENING" signal — bound so a hung Python import cannot
// wedge voice-loop start forever (#617).
const WAKEWORD_READY_TIMEOUT: Duration = Duration::from_secs(30);
let mut line = String::new();
reader.read_line(&mut line).await?;
match tokio::time::timeout(WAKEWORD_READY_TIMEOUT, reader.read_line(&mut line)).await {
Ok(Ok(_)) => {}
Ok(Err(e)) => {
let _ = child.kill().await;
anyhow::bail!("wake word listener stdout error: {e}");
}
Err(_) => {
let _ = child.kill().await;
anyhow::bail!(
"wake word listener timed out waiting for LISTENING after {}s",
WAKEWORD_READY_TIMEOUT.as_secs()
);
}
}
Comment on lines +260 to +273

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Retry startup failures instead of exiting voice mode.

After killing the child, anyhow::bail! returns from run_with_wakeword; therefore the outer restart loop at Line 225 never spawns a replacement. A hung import/model load will stop voice mode rather than recover. Route timeout/read failures through the retry path (sleep and continue), and apply the same handling to the malformed readiness branch at Lines 274-278.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/genie-core/src/voice_loop.rs` around lines 260 - 273, Update
run_with_wakeword’s wake-word startup handling so timeout, stdout read errors,
and malformed readiness responses kill the child, then sleep for the configured
retry delay and continue the outer restart loop instead of calling
anyhow::bail!. Preserve the successful readiness path and apply identical retry
behavior to all three failure branches.

if !line.trim().starts_with("LISTENING") {
eprintln!("[voice] Wake word listener failed: {}", line.trim());
let _ = child.kill().await;
Expand Down
Loading