diff --git a/src-tauri/src/services/acp/manager/dispatcher.rs b/src-tauri/src/services/acp/manager/dispatcher.rs index db0bd9d..0e6155f 100644 --- a/src-tauri/src/services/acp/manager/dispatcher.rs +++ b/src-tauri/src/services/acp/manager/dispatcher.rs @@ -19,6 +19,17 @@ use crate::services::acp::payloads::{ ToolResultPayload, ToolTitlePayload, }; +fn extract_user_message(raw: &str) -> &str { + const OPEN: &str = "\n"; + const CLOSE: &str = "\n"; + if let Some(start) = raw.find(OPEN) { + let inner = start + OPEN.len(); + if raw[inner..].ends_with(CLOSE) { + return &raw[inner..raw.len() - CLOSE.len()]; + } + } + raw +} fn model_options_from_select_options(options: &SessionConfigSelectOptions) -> Vec { match options { SessionConfigSelectOptions::Ungrouped(values) => values @@ -386,13 +397,14 @@ impl Client for SessionEventDispatcher { } } + let display_text = extract_user_message(&text.text); let message_id = uuid::Uuid::new_v4().to_string(); let _ = self.app_handle.emit( "acp:replay_user_message", serde_json::json!({ "sessionId": local_session_id, "messageId": message_id, - "text": text.text, + "text": display_text, }), ); } @@ -502,3 +514,6 @@ impl Client for SessionEventDispatcher { Ok(()) } } +#[cfg(test)] +#[path = "dispatcher_tests.rs"] +mod tests; diff --git a/src-tauri/src/services/acp/manager/dispatcher_tests.rs b/src-tauri/src/services/acp/manager/dispatcher_tests.rs new file mode 100644 index 0000000..7b68478 --- /dev/null +++ b/src-tauri/src/services/acp/manager/dispatcher_tests.rs @@ -0,0 +1,28 @@ +use super::*; + +#[test] +fn extract_user_message_strips_xml_wrapper() { + let wrapped = "\nYou are a helpful assistant.\n\n\n\nhello\n"; + assert_eq!(extract_user_message(wrapped), "hello"); +} + +#[test] +fn extract_user_message_multiline() { + let wrapped = "\nstuff\n\n\n\nline one\nline two\n"; + assert_eq!(extract_user_message(wrapped), "line one\nline two"); +} + +#[test] +fn extract_user_message_no_wrapper() { + assert_eq!(extract_user_message("plain text"), "plain text"); +} + +#[test] +fn extract_user_message_preserves_inner_delimiter() { + // User literally typed "" in their message — must not truncate. + let wrapped = "\nstuff\n\n\n\ncheck this tag: cool right?\n"; + assert_eq!( + extract_user_message(wrapped), + "check this tag: cool right?" + ); +}