mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Test agent TTS routing in settings layer
Signed-off-by: John Tennant <jtennant@squareup.com>
This commit is contained in:
committed by
John Tennant
parent
145e051fff
commit
c08885c2d9
@@ -0,0 +1,26 @@
|
||||
use super::{enqueue_agent_tts_text, normalize_agent_tts_text, MAX_TTS_TEXT_LEN};
|
||||
|
||||
#[tokio::test]
|
||||
async fn assistant_plain_text_routes_unchanged_into_voice_pipeline_boundary() {
|
||||
let (sender, receiver) = std::sync::mpsc::channel();
|
||||
let text = "A newly submitted assistant reply.".to_string();
|
||||
|
||||
enqueue_agent_tts_text(text.clone(), move |queued| {
|
||||
sender.send(queued).map_err(|error| error.to_string())
|
||||
})
|
||||
.await
|
||||
.expect("route assistant text");
|
||||
|
||||
assert_eq!(receiver.recv().expect("queued text"), text);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assistant_text_truncation_is_unicode_safe_before_voice_routing() {
|
||||
let input = "🦀".repeat(MAX_TTS_TEXT_LEN + 1);
|
||||
let output = normalize_agent_tts_text(input);
|
||||
assert_eq!(
|
||||
output.chars().count(),
|
||||
MAX_TTS_TEXT_LEN + "... message truncated.".chars().count()
|
||||
);
|
||||
assert!(output.ends_with("... message truncated."));
|
||||
}
|
||||
@@ -825,6 +825,25 @@ pub fn get_model_status(_state: State<'_, AppState>) -> Result<models::VoiceMode
|
||||
/// ~2000 chars ≈ 1–2 minutes of speech. Longer messages are truncated.
|
||||
const MAX_TTS_TEXT_LEN: usize = 2000;
|
||||
|
||||
fn normalize_agent_tts_text(text: String) -> String {
|
||||
if text.chars().count() > MAX_TTS_TEXT_LEN {
|
||||
let mut truncated: String = text.chars().take(MAX_TTS_TEXT_LEN).collect();
|
||||
truncated.push_str("... message truncated.");
|
||||
truncated
|
||||
} else {
|
||||
text
|
||||
}
|
||||
}
|
||||
|
||||
async fn enqueue_agent_tts_text<F>(text: String, enqueue: F) -> Result<(), String>
|
||||
where
|
||||
F: FnOnce(String) -> Result<(), String> + Send + 'static,
|
||||
{
|
||||
tokio::task::spawn_blocking(move || enqueue(text))
|
||||
.await
|
||||
.map_err(|error| format!("TTS enqueue task failed: {error}"))?
|
||||
}
|
||||
|
||||
/// Called by the WebView when it receives an incoming agent kind:9 message.
|
||||
/// Lazily starts the TTS pipeline if models are ready but the pipeline hasn't
|
||||
/// been created yet (e.g. models finished downloading after huddle started).
|
||||
@@ -834,13 +853,7 @@ const MAX_TTS_TEXT_LEN: usize = 2000;
|
||||
pub async fn speak_agent_message(text: String, state: State<'_, AppState>) -> Result<(), String> {
|
||||
// Truncate oversized messages — agents shouldn't monologue in a voice huddle.
|
||||
// Use char count (not byte length) to avoid panicking on multi-byte UTF-8.
|
||||
let text = if text.chars().count() > MAX_TTS_TEXT_LEN {
|
||||
let mut truncated: String = text.chars().take(MAX_TTS_TEXT_LEN).collect();
|
||||
truncated.push_str("... message truncated.");
|
||||
truncated
|
||||
} else {
|
||||
text
|
||||
};
|
||||
let text = normalize_agent_tts_text(text);
|
||||
|
||||
let needs_pipeline = {
|
||||
let hs = state.huddle()?;
|
||||
@@ -869,15 +882,17 @@ pub async fn speak_agent_message(text: String, state: State<'_, AppState>) -> Re
|
||||
let Some(sender) = sender else {
|
||||
return Ok(());
|
||||
};
|
||||
tokio::task::spawn_blocking(move || {
|
||||
enqueue_agent_tts_text(text, move |text| {
|
||||
sender
|
||||
.send(text)
|
||||
.map_err(|error| format!("TTS queue closed while waiting to enqueue: {error}"))
|
||||
})
|
||||
.await
|
||||
.map_err(|error| format!("TTS enqueue task failed: {error}"))?
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod agent_tts_routing_tests;
|
||||
|
||||
/// Add an agent to the active huddle.
|
||||
///
|
||||
/// Steps:
|
||||
|
||||
Reference in New Issue
Block a user