diff --git a/crates/openfang-channels/src/bridge.rs b/crates/openfang-channels/src/bridge.rs index cf1b383f..ffd908e9 100644 --- a/crates/openfang-channels/src/bridge.rs +++ b/crates/openfang-channels/src/bridge.rs @@ -890,8 +890,24 @@ async fn dispatch_message( // (which expire typing after ~5s) keep showing it during long LLM calls. let typing_task = spawn_typing_loop(adapter_arc.clone(), message.sender.clone()); + // Prepend sender context so the agent knows who is speaking. + // In group spaces this is essential for multi-user conversations. + let sender_name = &message.sender.display_name; + let sender_email = message + .metadata + .get("sender_email") + .and_then(|v| v.as_str()); + let prefixed_text = if !sender_name.is_empty() { + match sender_email { + Some(email) => format!("[From: {sender_name} <{email}>] {text}"), + None => format!("[From: {sender_name}] {text}"), + } + } else { + text.clone() + }; + // Send to agent and relay response - let result = handle.send_message(agent_id, &text).await; + let result = handle.send_message(agent_id, &prefixed_text).await; // Stop the typing refresh now that we have a response typing_task.abort(); diff --git a/crates/openfang-channels/tests/bridge_integration_test.rs b/crates/openfang-channels/tests/bridge_integration_test.rs index e4c64776..e954d4df 100644 --- a/crates/openfang-channels/tests/bridge_integration_test.rs +++ b/crates/openfang-channels/tests/bridge_integration_test.rs @@ -229,14 +229,23 @@ async fn test_bridge_dispatch_text_message() { let sent = adapter_ref.get_sent(); assert_eq!(sent.len(), 1, "Expected 1 response, got {}", sent.len()); assert_eq!(sent[0].0, "user1"); - assert_eq!(sent[0].1, "Echo: Hello agent!"); + // The bridge prepends sender identity: [From: Name] or [From: Name ] + assert!( + sent[0].1.contains("Hello agent!"), + "Response should contain original text, got: {}", + sent[0].1 + ); - // Verify: handle received the message + // Verify: handle received the message (with sender prefix) { let received = handle.received.lock().unwrap(); assert_eq!(received.len(), 1); assert_eq!(received[0].0, agent_id); - assert_eq!(received[0].1, "Hello agent!"); + assert!( + received[0].1.contains("Hello agent!"), + "Handle should receive text containing original message, got: {}", + received[0].1 + ); } manager.stop().await; @@ -486,7 +495,7 @@ async fn test_bridge_manager_lifecycle() { assert_eq!(sent.len(), 5, "Expected 5 responses, got {}", sent.len()); for (i, (_, text)) in sent.iter().enumerate() { - assert_eq!(*text, format!("Echo: message {i}")); + assert!(text.contains(&format!("message {i}")), "Expected 'message {i}' in: {text}"); } // Stop — should complete without hanging @@ -535,11 +544,11 @@ async fn test_bridge_multiple_adapters() { let tg_sent = tg_ref.get_sent(); assert_eq!(tg_sent.len(), 1); - assert_eq!(tg_sent[0].1, "Echo: from telegram"); + assert!(tg_sent[0].1.contains("from telegram"), "Expected 'from telegram' in: {}", tg_sent[0].1); let dc_sent = dc_ref.get_sent(); assert_eq!(dc_sent.len(), 1); - assert_eq!(dc_sent[0].1, "Echo: from discord"); + assert!(dc_sent[0].1.contains("from discord"), "Expected 'from discord' in: {}", dc_sent[0].1); manager.stop().await; }