diff --git a/crates/tui/src/commands/queue.rs b/crates/tui/src/commands/queue.rs index b1c76b8b6..b3804d059 100644 --- a/crates/tui/src/commands/queue.rs +++ b/crates/tui/src/commands/queue.rs @@ -1,5 +1,6 @@ //! Queue commands: queue list/edit/drop/clear +use crate::localization::{Locale, MessageId, tr}; use crate::tui::app::App; use super::CommandResult; @@ -7,6 +8,7 @@ use super::CommandResult; const PREVIEW_LIMIT: usize = 120; pub fn queue(app: &mut App, args: Option<&str>) -> CommandResult { + let locale = app.ui_locale; let arg = args.unwrap_or("").trim(); if arg.is_empty() || arg.eq_ignore_ascii_case("list") { return list_queue(app); @@ -19,27 +21,28 @@ pub fn queue(app: &mut App, args: Option<&str>) -> CommandResult { "edit" => edit_queue(app, parts.next()), "drop" | "remove" | "rm" => drop_queue(app, parts.next()), "clear" => clear_queue(app), - _ => CommandResult::error("Usage: /queue [list|edit |drop |clear]"), + _ => CommandResult::error(tr(locale, MessageId::CmdQueueUsage)), } } fn list_queue(app: &mut App) -> CommandResult { + let locale = app.ui_locale; let mut lines = Vec::new(); let queued = app.queued_message_count(); if let Some(draft) = app.queued_draft.as_ref() { - lines.push("Editing queued message:".to_string()); + lines.push(tr(locale, MessageId::CmdQueueDraftHeader).to_string()); lines.push(format!("- {}", truncate_preview(&draft.display))); } if queued == 0 { if lines.is_empty() { - return CommandResult::message("No queued messages"); + return CommandResult::message(tr(locale, MessageId::CmdQueueNoMessages)); } return CommandResult::message(lines.join("\n")); } - lines.push(format!("Queued messages ({queued}):")); + lines.push(tr(locale, MessageId::CmdQueueListHeader).replace("{count}", &queued.to_string())); for (idx, message) in app.queued_messages.iter().enumerate() { lines.push(format!( "{}. {}", @@ -48,70 +51,74 @@ fn list_queue(app: &mut App) -> CommandResult { )); } - lines.push("Tip: /queue edit to edit, /queue drop to remove".to_string()); + lines.push(tr(locale, MessageId::CmdQueueTip).to_string()); CommandResult::message(lines.join("\n")) } fn edit_queue(app: &mut App, index: Option<&str>) -> CommandResult { + let locale = app.ui_locale; if app.queued_draft.is_some() { - return CommandResult::error( - "Already editing a queued message. Send it or /queue clear to discard.", - ); + return CommandResult::error(tr(locale, MessageId::CmdQueueAlreadyEditing)); } - let index = match parse_index(index) { + let index = match parse_index(index, locale) { Ok(index) => index, Err(err) => return CommandResult::error(err), }; let Some(message) = app.remove_queued_message(index) else { - return CommandResult::error("Queued message not found"); + return CommandResult::error(tr(locale, MessageId::CmdQueueNotFound)); }; app.input = message.display.clone(); app.cursor_position = app.input.len(); app.queued_draft = Some(message); - app.status_message = Some(format!("Editing queued message {}", index + 1)); + let status = + tr(locale, MessageId::CmdQueueEditingStatus).replace("{index}", &(index + 1).to_string()); + app.status_message = Some(status); - CommandResult::message(format!( - "Editing queued message {} (press Enter to re-queue/send)", - index + 1 - )) + CommandResult::message( + tr(locale, MessageId::CmdQueueEditingMessage).replace("{index}", &(index + 1).to_string()), + ) } fn drop_queue(app: &mut App, index: Option<&str>) -> CommandResult { - let index = match parse_index(index) { + let locale = app.ui_locale; + let index = match parse_index(index, locale) { Ok(index) => index, Err(err) => return CommandResult::error(err), }; if app.remove_queued_message(index).is_none() { - return CommandResult::error("Queued message not found"); + return CommandResult::error(tr(locale, MessageId::CmdQueueNotFound)); } - CommandResult::message(format!("Dropped queued message {}", index + 1)) + CommandResult::message( + tr(locale, MessageId::CmdQueueDropped).replace("{index}", &(index + 1).to_string()), + ) } fn clear_queue(app: &mut App) -> CommandResult { + let locale = app.ui_locale; let queued = app.queued_message_count(); let had_draft = app.queued_draft.take().is_some(); app.queued_messages.clear(); if queued == 0 && !had_draft { - return CommandResult::message("Queue already empty"); + return CommandResult::message(tr(locale, MessageId::CmdQueueAlreadyEmpty)); } - CommandResult::message("Queue cleared") + CommandResult::message(tr(locale, MessageId::CmdQueueCleared)) } -fn parse_index(input: Option<&str>) -> Result { +fn parse_index(input: Option<&str>, locale: Locale) -> Result { let Some(input) = input else { - return Err("Missing index. Usage: /queue edit or /queue drop "); + return Err(tr(locale, MessageId::CmdQueueMissingIndex).to_string()); }; let raw = input .parse::() - .map_err(|_| "Index must be a positive number")?; + .map_err(|_| tr(locale, MessageId::CmdQueueIndexPositive).to_string())?; if raw == 0 { - return Err("Index must be >= 1"); + return Err(tr(locale, MessageId::CmdQueueIndexMin).to_string()); } Ok(raw - 1) } @@ -164,16 +171,18 @@ mod tests { fn test_queue_list_empty() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; let result = queue(&mut app, None); assert!(result.message.is_some()); let msg = result.message.unwrap(); - assert!(msg.contains("No queued messages")); + assert!(msg.contains(tr(app.ui_locale, MessageId::CmdQueueNoMessages))); } #[test] fn test_queue_list_with_messages() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; app.queued_messages .push_back(QueuedMessage::new("First message".to_string(), None)); app.queued_messages @@ -181,7 +190,9 @@ mod tests { let result = queue(&mut app, Some("list")); assert!(result.message.is_some()); let msg = result.message.unwrap(); - assert!(msg.contains("Queued messages (2)")); + assert!( + msg.contains(&tr(app.ui_locale, MessageId::CmdQueueListHeader).replace("{count}", "2")) + ); assert!(msg.contains("1. First message")); assert!(msg.contains("2. Second message")); } @@ -190,24 +201,29 @@ mod tests { fn test_queue_edit_missing_index() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; app.queued_messages .push_back(QueuedMessage::new("Test".to_string(), None)); let result = queue(&mut app, Some("edit")); assert!(result.message.is_some()); - assert!(result.message.unwrap().contains("Missing index")); + let msg = result.message.unwrap(); + assert!( + msg.contains(tr(Locale::En, MessageId::CmdQueueMissingIndex)), + "msg={msg:?}" + ); } #[test] fn test_queue_edit_invalid_index() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; let result = queue(&mut app, Some("edit abc")); assert!(result.message.is_some()); + let msg = result.message.unwrap(); assert!( - result - .message - .unwrap() - .contains("must be a positive number") + msg.contains(tr(Locale::En, MessageId::CmdQueueIndexPositive)), + "msg={msg:?}" ); } @@ -215,15 +231,21 @@ mod tests { fn test_queue_edit_not_found() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; let result = queue(&mut app, Some("edit 1")); assert!(result.message.is_some()); - assert!(result.message.unwrap().contains("not found")); + let msg = result.message.unwrap(); + assert!( + msg.contains(tr(Locale::En, MessageId::CmdQueueNotFound)), + "msg={msg:?}" + ); } #[test] fn test_queue_edit_already_editing() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; app.queued_messages .push_back(QueuedMessage::new("First".to_string(), None)); app.queued_messages @@ -233,13 +255,18 @@ mod tests { // Try to edit another let result = queue(&mut app, Some("edit 2")); assert!(result.message.is_some()); - assert!(result.message.unwrap().contains("Already editing")); + let msg = result.message.unwrap(); + assert!( + msg.contains(tr(Locale::En, MessageId::CmdQueueAlreadyEditing)), + "msg={msg:?}" + ); } #[test] fn test_queue_edit_success() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; app.queued_messages .push_back(QueuedMessage::new("Original message".to_string(), None)); let result = queue(&mut app, Some("edit 1")); @@ -253,12 +280,17 @@ mod tests { fn test_queue_drop_success() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; app.queued_messages .push_back(QueuedMessage::new("To drop".to_string(), None)); let initial_count = app.queued_messages.len(); let result = queue(&mut app, Some("drop 1")); assert!(result.message.is_some()); - assert!(result.message.unwrap().contains("Dropped queued message")); + let msg = result.message.unwrap(); + assert!( + msg.contains(&tr(Locale::En, MessageId::CmdQueueDropped).replace("{index}", "1")), + "msg={msg:?}" + ); assert_eq!(app.queued_messages.len(), initial_count - 1); } @@ -266,13 +298,18 @@ mod tests { fn test_queue_clear() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; app.queued_messages .push_back(QueuedMessage::new("Message 1".to_string(), None)); app.queued_messages .push_back(QueuedMessage::new("Message 2".to_string(), None)); let result = queue(&mut app, Some("clear")); assert!(result.message.is_some()); - assert!(result.message.unwrap().contains("Queue cleared")); + let msg = result.message.unwrap(); + assert!( + msg.contains(tr(Locale::En, MessageId::CmdQueueCleared)), + "msg={msg:?}" + ); assert!(app.queued_messages.is_empty()); } @@ -280,9 +317,29 @@ mod tests { fn test_queue_clear_already_empty() { let tmpdir = TempDir::new().unwrap(); let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::En; let result = queue(&mut app, Some("clear")); assert!(result.message.is_some()); - assert!(result.message.unwrap().contains("Queue already empty")); + let msg = result.message.unwrap(); + assert!( + msg.contains(tr(Locale::En, MessageId::CmdQueueAlreadyEmpty)), + "msg={msg:?}" + ); + } + + #[test] + fn queue_messages_are_localized() { + let tmpdir = TempDir::new().unwrap(); + let mut app = create_test_app_with_tmpdir(&tmpdir); + app.ui_locale = Locale::ZhHans; + app.queued_messages + .push_back(QueuedMessage::new("M1".to_string(), None)); + app.queued_messages + .push_back(QueuedMessage::new("M2".to_string(), None)); + let result = queue(&mut app, Some("list")); + let msg = result.message.unwrap(); + assert!(msg.contains("已排队的消息"), "zh list header: {msg}"); + assert!(msg.contains("提示"), "zh tip: {msg}"); } #[test] diff --git a/crates/tui/src/localization.rs b/crates/tui/src/localization.rs index 5e67b571e..535591576 100644 --- a/crates/tui/src/localization.rs +++ b/crates/tui/src/localization.rs @@ -290,6 +290,21 @@ pub enum MessageId { CmdThemeDescription, CmdProviderDescription, CmdQueueDescription, + CmdQueueUsage, + CmdQueueDraftHeader, + CmdQueueNoMessages, + CmdQueueListHeader, + CmdQueueTip, + CmdQueueAlreadyEditing, + CmdQueueNotFound, + CmdQueueEditingStatus, + CmdQueueEditingMessage, + CmdQueueDropped, + CmdQueueAlreadyEmpty, + CmdQueueCleared, + CmdQueueMissingIndex, + CmdQueueIndexPositive, + CmdQueueIndexMin, CmdRecallDescription, CmdRelayDescription, CmdRenameDescription, @@ -554,6 +569,21 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[ MessageId::CmdNoteDescription, MessageId::CmdProviderDescription, MessageId::CmdQueueDescription, + MessageId::CmdQueueUsage, + MessageId::CmdQueueDraftHeader, + MessageId::CmdQueueNoMessages, + MessageId::CmdQueueListHeader, + MessageId::CmdQueueTip, + MessageId::CmdQueueAlreadyEditing, + MessageId::CmdQueueNotFound, + MessageId::CmdQueueEditingStatus, + MessageId::CmdQueueEditingMessage, + MessageId::CmdQueueDropped, + MessageId::CmdQueueAlreadyEmpty, + MessageId::CmdQueueCleared, + MessageId::CmdQueueMissingIndex, + MessageId::CmdQueueIndexPositive, + MessageId::CmdQueueIndexMin, MessageId::CmdRecallDescription, MessageId::CmdRelayDescription, MessageId::CmdRenameDescription, @@ -1035,6 +1065,27 @@ fn english(id: MessageId) -> &'static str { "Switch or view the active LLM backend (deepseek | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "View or edit queued messages", + MessageId::CmdQueueUsage => "Usage: /queue [list|edit |drop |clear]", + MessageId::CmdQueueDraftHeader => "Editing queued message:", + MessageId::CmdQueueNoMessages => "No queued messages", + MessageId::CmdQueueListHeader => "Queued messages ({count}):", + MessageId::CmdQueueTip => "Tip: /queue edit to edit, /queue drop to remove", + MessageId::CmdQueueAlreadyEditing => { + "Already editing a queued message. Send it or /queue clear to discard." + } + MessageId::CmdQueueNotFound => "Queued message not found", + MessageId::CmdQueueEditingStatus => "Editing queued message {index}", + MessageId::CmdQueueEditingMessage => { + "Editing queued message {index} (press Enter to re-queue/send)" + } + MessageId::CmdQueueDropped => "Dropped queued message {index}", + MessageId::CmdQueueAlreadyEmpty => "Queue already empty", + MessageId::CmdQueueCleared => "Queue cleared", + MessageId::CmdQueueMissingIndex => { + "Missing index. Usage: /queue edit or /queue drop " + } + MessageId::CmdQueueIndexPositive => "Index must be a positive number", + MessageId::CmdQueueIndexMin => "Index must be >= 1", MessageId::CmdRecallDescription => "Search prior cycle archives (BM25 over message text)", MessageId::CmdRelayDescription => "Create a session relay (接力) for a fresh thread", MessageId::CmdRenameDescription => "Rename the current session", @@ -1443,6 +1494,27 @@ fn vietnamese(id: MessageId) -> Option<&'static str> { "Chuyển đổi hoặc xem backend LLM đang hoạt động (deepseek | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "Xem hoặc chỉnh sửa các tin nhắn đang chờ xử lý", + MessageId::CmdQueueUsage => "Cách dùng: /queue [list|edit |drop |clear]", + MessageId::CmdQueueDraftHeader => "Đang chỉnh sửa tin nhắn đang chờ:", + MessageId::CmdQueueNoMessages => "Không có tin nhắn đang chờ", + MessageId::CmdQueueListHeader => "Tin nhắn đang chờ ({count}):", + MessageId::CmdQueueTip => "Mẹo: /queue edit để sửa, /queue drop để xóa", + MessageId::CmdQueueAlreadyEditing => { + "Đã đang chỉnh sửa một tin nhắn đang chờ. Hãy gửi nó hoặc dùng /queue clear để hủy." + } + MessageId::CmdQueueNotFound => "Không tìm thấy tin nhắn đang chờ", + MessageId::CmdQueueEditingStatus => "Đang chỉnh sửa tin nhắn đang chờ {index}", + MessageId::CmdQueueEditingMessage => { + "Đang chỉnh sửa tin nhắn đang chờ {index} (nhấn Enter để xếp lại hàng/gửi)" + } + MessageId::CmdQueueDropped => "Đã xóa tin nhắn đang chờ {index}", + MessageId::CmdQueueAlreadyEmpty => "Hàng đợi đã trống", + MessageId::CmdQueueCleared => "Đã xóa hàng đợi", + MessageId::CmdQueueMissingIndex => { + "Thiếu chỉ mục. Cách dùng: /queue edit hoặc /queue drop " + } + MessageId::CmdQueueIndexPositive => "Chỉ mục phải là số dương", + MessageId::CmdQueueIndexMin => "Chỉ mục phải >= 1", MessageId::CmdRecallDescription => { "Tìm kiếm kho lưu trữ chu kỳ trước (BM25 trên văn bản tin nhắn)" } @@ -1878,6 +1950,27 @@ fn japanese(id: MessageId) -> Option<&'static str> { "現在の LLM バックエンドを切り替え・確認(deepseek | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "キューされたメッセージを確認・編集", + MessageId::CmdQueueUsage => "使用方法: /queue [list|edit |drop |clear]", + MessageId::CmdQueueDraftHeader => "キューされたメッセージを編集中:", + MessageId::CmdQueueNoMessages => "キューされたメッセージはありません", + MessageId::CmdQueueListHeader => "キューされたメッセージ ({count}):", + MessageId::CmdQueueTip => "ヒント: /queue edit で編集、/queue drop で削除", + MessageId::CmdQueueAlreadyEditing => { + "すでにキューされたメッセージを編集中です。送信するか /queue clear で破棄してください。" + } + MessageId::CmdQueueNotFound => "キューされたメッセージが見つかりません", + MessageId::CmdQueueEditingStatus => "キューされたメッセージ {index} を編集中", + MessageId::CmdQueueEditingMessage => { + "キューされたメッセージ {index} を編集中(Enter で再キュー/送信)" + } + MessageId::CmdQueueDropped => "キューされたメッセージ {index} を削除しました", + MessageId::CmdQueueAlreadyEmpty => "キューはすでに空です", + MessageId::CmdQueueCleared => "キューをクリアしました", + MessageId::CmdQueueMissingIndex => { + "インデックスが指定されていません。使用方法: /queue edit または /queue drop " + } + MessageId::CmdQueueIndexPositive => "インデックスは正の数値である必要があります", + MessageId::CmdQueueIndexMin => "インデックスは 1 以上である必要があります", MessageId::CmdRecallDescription => { "過去のサイクルアーカイブを検索(メッセージ本文への BM25 検索)" } @@ -2253,6 +2346,25 @@ fn chinese_simplified(id: MessageId) -> Option<&'static str> { "切换或查看当前 LLM 后端(deepseek | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "查看或编辑已排队的消息", + MessageId::CmdQueueUsage => "用法: /queue [list|edit |drop |clear]", + MessageId::CmdQueueDraftHeader => "正在编辑已排队的消息:", + MessageId::CmdQueueNoMessages => "没有已排队的消息", + MessageId::CmdQueueListHeader => "已排队的消息 ({count}):", + MessageId::CmdQueueTip => "提示: /queue edit 编辑, /queue drop 删除", + MessageId::CmdQueueAlreadyEditing => { + "已在编辑一条已排队的消息。请先发送或使用 /queue clear 放弃。" + } + MessageId::CmdQueueNotFound => "未找到已排队的消息", + MessageId::CmdQueueEditingStatus => "正在编辑已排队的消息 {index}", + MessageId::CmdQueueEditingMessage => { + "正在编辑已排队的消息 {index}(按 Enter 重新排队/发送)" + } + MessageId::CmdQueueDropped => "已删除已排队的消息 {index}", + MessageId::CmdQueueAlreadyEmpty => "队列已空", + MessageId::CmdQueueCleared => "队列已清空", + MessageId::CmdQueueMissingIndex => "缺少索引。用法: /queue edit 或 /queue drop ", + MessageId::CmdQueueIndexPositive => "索引必须为正数", + MessageId::CmdQueueIndexMin => "索引必须 >= 1", MessageId::CmdRecallDescription => "搜索此前的循环归档(基于消息文本的 BM25 检索)", MessageId::CmdRelayDescription => "为新线程创建会话接力摘要", MessageId::CmdRenameDescription => "重命名当前会话", @@ -2614,6 +2726,27 @@ fn portuguese_brazil(id: MessageId) -> Option<&'static str> { "Trocar ou exibir o backend LLM ativo (deepseek | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "Ver ou editar mensagens enfileiradas", + MessageId::CmdQueueUsage => "Uso: /queue [list|edit |drop |clear]", + MessageId::CmdQueueDraftHeader => "Editando mensagem enfileirada:", + MessageId::CmdQueueNoMessages => "Nenhuma mensagem enfileirada", + MessageId::CmdQueueListHeader => "Mensagens enfileiradas ({count}):", + MessageId::CmdQueueTip => "Dica: /queue edit para editar, /queue drop para remover", + MessageId::CmdQueueAlreadyEditing => { + "Já está editando uma mensagem enfileirada. Envie-a ou use /queue clear para descartar." + } + MessageId::CmdQueueNotFound => "Mensagem enfileirada não encontrada", + MessageId::CmdQueueEditingStatus => "Editando mensagem enfileirada {index}", + MessageId::CmdQueueEditingMessage => { + "Editando mensagem enfileirada {index} (pressione Enter para re-enfileirar/enviar)" + } + MessageId::CmdQueueDropped => "Mensagem enfileirada {index} removida", + MessageId::CmdQueueAlreadyEmpty => "Fila já está vazia", + MessageId::CmdQueueCleared => "Fila limpa", + MessageId::CmdQueueMissingIndex => { + "Índice ausente. Uso: /queue edit ou /queue drop " + } + MessageId::CmdQueueIndexPositive => "O índice deve ser um número positivo", + MessageId::CmdQueueIndexMin => "O índice deve ser >= 1", MessageId::CmdRecallDescription => { "Buscar arquivos de ciclos anteriores (BM25 sobre o texto das mensagens)" } @@ -3039,6 +3172,29 @@ fn spanish_latin_america(id: MessageId) -> Option<&'static str> { "Cambiar o mostrar el backend LLM activo (deepseek | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "Ver o editar mensajes en cola", + MessageId::CmdQueueUsage => "Uso: /queue [list|edit |drop |clear]", + MessageId::CmdQueueDraftHeader => "Editando mensaje en cola:", + MessageId::CmdQueueNoMessages => "No hay mensajes en cola", + MessageId::CmdQueueListHeader => "Mensajes en cola ({count}):", + MessageId::CmdQueueTip => { + "Consejo: /queue edit para editar, /queue drop para eliminar" + } + MessageId::CmdQueueAlreadyEditing => { + "Ya estás editando un mensaje en cola. Envíalo o usa /queue clear para descartarlo." + } + MessageId::CmdQueueNotFound => "Mensaje en cola no encontrado", + MessageId::CmdQueueEditingStatus => "Editando mensaje en cola {index}", + MessageId::CmdQueueEditingMessage => { + "Editando mensaje en cola {index} (presiona Enter para re-encolar/enviar)" + } + MessageId::CmdQueueDropped => "Mensaje en cola {index} eliminado", + MessageId::CmdQueueAlreadyEmpty => "La cola ya está vacía", + MessageId::CmdQueueCleared => "Cola limpiada", + MessageId::CmdQueueMissingIndex => { + "Índice faltante. Uso: /queue edit o /queue drop " + } + MessageId::CmdQueueIndexPositive => "El índice debe ser un número positivo", + MessageId::CmdQueueIndexMin => "El índice debe ser >= 1", MessageId::CmdRecallDescription => { "Buscar archivos de ciclos anteriores (BM25 sobre el texto de los mensajes)" } diff --git a/crates/tui/src/tui/ui/tests.rs b/crates/tui/src/tui/ui/tests.rs index 166031371..eb727e589 100644 --- a/crates/tui/src/tui/ui/tests.rs +++ b/crates/tui/src/tui/ui/tests.rs @@ -2512,11 +2512,12 @@ fn turn_liveness_leaves_active_turn_running() { #[test] fn turn_liveness_uses_recent_turn_activity_not_turn_start() { let mut app = create_test_app(); - let now = Instant::now(); app.is_loading = true; app.runtime_turn_status = Some("in_progress".to_string()); - app.turn_started_at = Some(now - TURN_STALL_WATCHDOG_TIMEOUT - Duration::from_secs(30)); - app.turn_last_activity_at = Some(now - Duration::from_secs(1)); + app.turn_started_at = Some(Instant::now()); + app.turn_last_activity_at = + Some(app.turn_started_at.unwrap() + TURN_STALL_WATCHDOG_TIMEOUT + Duration::from_secs(29)); + let now = app.turn_last_activity_at.unwrap() + Duration::from_secs(1); let recovered = reconcile_turn_liveness(&mut app, now, false); @@ -2529,11 +2530,14 @@ fn turn_liveness_uses_recent_turn_activity_not_turn_start() { #[test] fn turn_liveness_does_not_abort_running_tool() { let mut app = create_test_app(); - let now = Instant::now(); app.is_loading = true; app.runtime_turn_status = Some("in_progress".to_string()); - app.turn_started_at = Some(now - TURN_STALL_WATCHDOG_TIMEOUT - Duration::from_secs(30)); + app.turn_started_at = Some(Instant::now()); app.turn_last_activity_at = app.turn_started_at; + let now = app.turn_started_at.unwrap() + + TURN_STALL_WATCHDOG_TIMEOUT + + Duration::from_secs(30) + + Duration::from_secs(1); let mut active = ActiveCell::new(); active.push_tool( "tool-1",