From 2bc5d49916160f7bb781369a9bd6132f24e84417 Mon Sep 17 00:00:00 2001 From: Khaliq Date: Wed, 25 Mar 2026 15:38:04 +0100 Subject: [PATCH 1/7] fix(wrap): add RELAY_SKIP_PROMPT and self-echo filtering Two fixes for the wrap command when used in interactive terminal environments (e.g. Superset desktop app): 1. RELAY_SKIP_PROMPT=1 env var suppresses the block that wraps injected messages. In interactive terminals, this XML noise confuses both the agent and the user. 2. Add RELAY_AGENT_NAME to self_names so messages sent by the agent's own MCP server (which registers with the same name) are filtered as self-echo instead of being re-injected into the PTY. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/wrap.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index f549a1871..41cfa2cb0 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -3,7 +3,7 @@ use std::time::{Duration, Instant}; use super::*; use crate::helpers::{ - check_echo_in_output, floor_char_boundary, format_injection_with_workspace, ActivityDetector, + check_echo_in_output, floor_char_boundary, format_injection_for_worker_with_workspace, format_injection_with_workspace, ActivityDetector, DeliveryOutcome, PendingActivity, PendingVerification, ThrottleState, ACTIVITY_BUFFER_KEEP_BYTES, ACTIVITY_BUFFER_MAX_BYTES, ACTIVITY_WINDOW, MAX_VERIFICATION_ATTEMPTS, VERIFICATION_WINDOW, @@ -546,6 +546,7 @@ pub(crate) async fn run_wrap( let requested_name = std::env::var("RELAY_AGENT_NAME").unwrap_or_else(|_| resolved_cli.clone()); let channels = std::env::var("RELAY_CHANNELS").unwrap_or_else(|_| "general".to_string()); let channel_list = channels_from_csv(&channels); + let skip_prompt = env_flag_enabled("RELAY_SKIP_PROMPT"); eprintln!( "[agent-relay] wrapping {} (agent: {}, channels: {:?})", @@ -578,6 +579,16 @@ pub(crate) async fn run_wrap( workspaces, mut ws_inbound_rx, } = relay; + // Ensure the requested agent name (from RELAY_AGENT_NAME) is in self_names + // so that messages sent by the MCP server child (which registers with the + // same name) are recognized as self-echo and filtered out. + let workspaces: Vec = workspaces + .into_iter() + .map(|mut ws| { + ws.self_names.insert(requested_name.clone()); + ws + }) + .collect(); let workspace_lookup: std::collections::HashMap = workspaces .iter() .cloned() @@ -1072,11 +1083,14 @@ pub(crate) async fn run_wrap( pty_auto.auto_suggestion_visible = false; } tracing::debug!("relay from {} → {}", pending.from, pending.target); - let injection = format_injection_with_workspace( + let injection = format_injection_for_worker_with_workspace( &pending.from, &pending.event_id, &pending.body, &pending.target, + !skip_prompt, // include_reminder + true, // pre_registered + None, // assigned_name pending.workspace_id.as_deref(), pending.workspace_alias.as_deref(), ); @@ -1171,11 +1185,14 @@ pub(crate) async fn run_wrap( // Re-inject retries for mut pv in retry_queue { tokio::time::sleep(throttle.delay()).await; - let injection = format_injection_with_workspace( + let injection = format_injection_for_worker_with_workspace( &pv.from, &pv.event_id, &pv.body, &pv.target, + !skip_prompt, + true, + None, pv.workspace_id.as_deref(), pv.workspace_alias.as_deref(), ); From effe2aa97020687a42775a1922704050459a6370 Mon Sep 17 00:00:00 2001 From: Khaliq Date: Wed, 25 Mar 2026 15:48:27 +0100 Subject: [PATCH 2/7] fix(wrap): add DM routing filter Only deliver DMs addressed to this agent. Previously all DMs on the workspace were injected into every agent's PTY. Channel messages (target starts with '#') are still broadcast to all subscribers. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/wrap.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/wrap.rs b/src/wrap.rs index 41cfa2cb0..ca9cb047e 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -1035,6 +1035,20 @@ pub(crate) async fn run_wrap( continue; } + // DM routing: only deliver DMs addressed to this agent. + // Channel messages (target starts with '#') are broadcast + // to all subscribers. + if !mapped.target.starts_with('#') + && !workspace_self_names.contains(&mapped.target) + { + tracing::debug!( + target = %mapped.target, + self_names = ?workspace_self_names, + "skipping DM not addressed to this agent" + ); + continue; + } + let delivery_id = format!("wrap_{}", mapped.event_id); tracing::debug!( delivery_id = %delivery_id, From 1e82b70ced7cab9eecc8a11f4166feb77bc012fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 25 Mar 2026 14:52:28 +0000 Subject: [PATCH 3/7] style: auto-format Rust code with cargo fmt --- src/wrap.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index ca9cb047e..99d2d7035 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -3,10 +3,10 @@ use std::time::{Duration, Instant}; use super::*; use crate::helpers::{ - check_echo_in_output, floor_char_boundary, format_injection_for_worker_with_workspace, format_injection_with_workspace, ActivityDetector, - DeliveryOutcome, PendingActivity, PendingVerification, ThrottleState, - ACTIVITY_BUFFER_KEEP_BYTES, ACTIVITY_BUFFER_MAX_BYTES, ACTIVITY_WINDOW, - MAX_VERIFICATION_ATTEMPTS, VERIFICATION_WINDOW, + check_echo_in_output, floor_char_boundary, format_injection_for_worker_with_workspace, + format_injection_with_workspace, ActivityDetector, DeliveryOutcome, PendingActivity, + PendingVerification, ThrottleState, ACTIVITY_BUFFER_KEEP_BYTES, ACTIVITY_BUFFER_MAX_BYTES, + ACTIVITY_WINDOW, MAX_VERIFICATION_ATTEMPTS, VERIFICATION_WINDOW, }; // PTY auto-response constants (shared by wrap and pty workers) From f78f7b13f4ac050530ec1b914b6d3cae9f15d8bf Mon Sep 17 00:00:00 2001 From: Khaliq Date: Wed, 25 Mar 2026 16:23:37 +0100 Subject: [PATCH 4/7] fix: DM routing filter now allows thread replies, presence events, and conversation_id targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Devin review caught that the filter was too aggressive — it silently dropped messages with empty targets (presence), 'thread' targets (thread replies), and dm_/conv_ prefixed targets (conversation_id fallback). Only drop messages clearly addressed to a different agent. --- src/wrap.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index 99d2d7035..c018bf46e 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -1037,8 +1037,13 @@ pub(crate) async fn run_wrap( // DM routing: only deliver DMs addressed to this agent. // Channel messages (target starts with '#') are broadcast - // to all subscribers. - if !mapped.target.starts_with('#') + // to all subscribers. Allow through: empty targets (presence), + // thread replies, conversation_id fallbacks. + if !mapped.target.is_empty() + && !mapped.target.starts_with('#') + && mapped.target != "thread" + && !mapped.target.starts_with("dm_") + && !mapped.target.starts_with("conv_") && !workspace_self_names.contains(&mapped.target) { tracing::debug!( From 184f502cf5542b2ba0f918681eff6be194699c71 Mon Sep 17 00:00:00 2001 From: Khaliq Date: Wed, 25 Mar 2026 17:14:06 +0100 Subject: [PATCH 5/7] fix: remove unused format_injection_with_workspace import and function --- src/helpers.rs | 21 --------------------- src/wrap.rs | 2 +- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 806227cec..d2f7570f3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -532,27 +532,6 @@ pub(crate) fn format_injection(from: &str, event_id: &str, body: &str, target: & format_injection_with_reminder(from, event_id, body, target, true) } -pub(crate) fn format_injection_with_workspace( - from: &str, - event_id: &str, - body: &str, - target: &str, - workspace_id: Option<&str>, - workspace_alias: Option<&str>, -) -> String { - format_injection_for_worker_with_workspace( - from, - event_id, - body, - target, - true, - true, - None, - workspace_id, - workspace_alias, - ) -} - #[cfg_attr(not(test), allow(dead_code))] pub(crate) fn format_injection_with_reminder( from: &str, diff --git a/src/wrap.rs b/src/wrap.rs index c018bf46e..4e133f636 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -4,7 +4,7 @@ use std::time::{Duration, Instant}; use super::*; use crate::helpers::{ check_echo_in_output, floor_char_boundary, format_injection_for_worker_with_workspace, - format_injection_with_workspace, ActivityDetector, DeliveryOutcome, PendingActivity, + ActivityDetector, DeliveryOutcome, PendingActivity, PendingVerification, ThrottleState, ACTIVITY_BUFFER_KEEP_BYTES, ACTIVITY_BUFFER_MAX_BYTES, ACTIVITY_WINDOW, MAX_VERIFICATION_ATTEMPTS, VERIFICATION_WINDOW, }; From 6508b0acaa701635ce8f8f9499977452dbf83388 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 25 Mar 2026 16:14:38 +0000 Subject: [PATCH 6/7] style: auto-format Rust code with cargo fmt --- src/wrap.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wrap.rs b/src/wrap.rs index 4e133f636..50d4d681c 100644 --- a/src/wrap.rs +++ b/src/wrap.rs @@ -4,9 +4,9 @@ use std::time::{Duration, Instant}; use super::*; use crate::helpers::{ check_echo_in_output, floor_char_boundary, format_injection_for_worker_with_workspace, - ActivityDetector, DeliveryOutcome, PendingActivity, - PendingVerification, ThrottleState, ACTIVITY_BUFFER_KEEP_BYTES, ACTIVITY_BUFFER_MAX_BYTES, - ACTIVITY_WINDOW, MAX_VERIFICATION_ATTEMPTS, VERIFICATION_WINDOW, + ActivityDetector, DeliveryOutcome, PendingActivity, PendingVerification, ThrottleState, + ACTIVITY_BUFFER_KEEP_BYTES, ACTIVITY_BUFFER_MAX_BYTES, ACTIVITY_WINDOW, + MAX_VERIFICATION_ATTEMPTS, VERIFICATION_WINDOW, }; // PTY auto-response constants (shared by wrap and pty workers) From ece1cab86eff87069978a03b5305f41f621359aa Mon Sep 17 00:00:00 2001 From: Khaliq Date: Wed, 25 Mar 2026 17:30:35 +0100 Subject: [PATCH 7/7] trail: DM routing filter fix trajectory --- .../completed/2026-03/traj_hn0583gzi86w.json | 65 +++++++++++++++++++ .../completed/2026-03/traj_hn0583gzi86w.md | 24 +++++++ .trajectories/index.json | 9 ++- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 .trajectories/completed/2026-03/traj_hn0583gzi86w.json create mode 100644 .trajectories/completed/2026-03/traj_hn0583gzi86w.md diff --git a/.trajectories/completed/2026-03/traj_hn0583gzi86w.json b/.trajectories/completed/2026-03/traj_hn0583gzi86w.json new file mode 100644 index 000000000..046446477 --- /dev/null +++ b/.trajectories/completed/2026-03/traj_hn0583gzi86w.json @@ -0,0 +1,65 @@ +{ + "id": "traj_hn0583gzi86w", + "version": 1, + "task": { + "title": "Fix DM routing filter in wrap.rs — allow thread replies, presence events, and conversation_id targets" + }, + "status": "completed", + "startedAt": "2026-03-25T16:25:02.609Z", + "agents": [ + { + "name": "default", + "role": "lead", + "joinedAt": "2026-03-25T16:25:26.589Z" + } + ], + "chapters": [ + { + "id": "chap_7w31qsrd314j", + "title": "Work", + "agentName": "default", + "startedAt": "2026-03-25T16:25:26.589Z", + "events": [ + { + "ts": 1774455926589, + "type": "decision", + "content": "Widen DM filter rather than restructure — add pass-through for empty targets (presence), 'thread' synthetic targets, dm_/conv_ prefixed conversation IDs. Also removed dead code: format_injection_with_workspace import and function.: Widen DM filter rather than restructure — add pass-through for empty targets (presence), 'thread' synthetic targets, dm_/conv_ prefixed conversation IDs. Also removed dead code: format_injection_with_workspace import and function.", + "raw": { + "question": "Widen DM filter rather than restructure — add pass-through for empty targets (presence), 'thread' synthetic targets, dm_/conv_ prefixed conversation IDs. Also removed dead code: format_injection_with_workspace import and function.", + "chosen": "Widen DM filter rather than restructure — add pass-through for empty targets (presence), 'thread' synthetic targets, dm_/conv_ prefixed conversation IDs. Also removed dead code: format_injection_with_workspace import and function.", + "alternatives": [], + "reasoning": "" + }, + "significance": "high" + }, + { + "ts": 1774456153059, + "type": "decision", + "content": "Expanded DM filter to allow empty targets (presence), thread synthetic target, and dm_/conv_ prefixed conversation_id fallbacks. Removed unused format_injection_with_workspace function and import.: Expanded DM filter to allow empty targets (presence), thread synthetic target, and dm_/conv_ prefixed conversation_id fallbacks. Removed unused format_injection_with_workspace function and import.", + "raw": { + "question": "Expanded DM filter to allow empty targets (presence), thread synthetic target, and dm_/conv_ prefixed conversation_id fallbacks. Removed unused format_injection_with_workspace function and import.", + "chosen": "Expanded DM filter to allow empty targets (presence), thread synthetic target, and dm_/conv_ prefixed conversation_id fallbacks. Removed unused format_injection_with_workspace function and import.", + "alternatives": [], + "reasoning": "" + }, + "significance": "high" + } + ], + "endedAt": "2026-03-25T16:29:26.110Z" + } + ], + "commits": [], + "filesChanged": [], + "projectId": "/Users/khaliqgant/Projects/Agent Workforce/relay", + "tags": [], + "_trace": { + "startRef": "184f502cf5542b2ba0f918681eff6be194699c71", + "endRef": "184f502cf5542b2ba0f918681eff6be194699c71" + }, + "completedAt": "2026-03-25T16:29:26.110Z", + "retrospective": { + "summary": "Fixed DM routing filter and cleaned up dead code per Devin review on PR #641", + "approach": "Added explicit exceptions for empty targets, thread, dm_/conv_ prefixes. Removed unused format_injection_with_workspace.", + "confidence": 0.95 + } +} \ No newline at end of file diff --git a/.trajectories/completed/2026-03/traj_hn0583gzi86w.md b/.trajectories/completed/2026-03/traj_hn0583gzi86w.md new file mode 100644 index 000000000..c66f6cdd8 --- /dev/null +++ b/.trajectories/completed/2026-03/traj_hn0583gzi86w.md @@ -0,0 +1,24 @@ +# Trajectory: Fix DM routing filter in wrap.rs — allow thread replies, presence events, and conversation_id targets + +> **Status:** ✅ Completed +> **Confidence:** 95% +> **Started:** March 25, 2026 at 05:25 PM +> **Completed:** March 25, 2026 at 05:29 PM + +--- + +## Summary + +Fixed DM routing filter and cleaned up dead code per Devin review on PR #641 + +**Approach:** Added explicit exceptions for empty targets, thread, dm_/conv_ prefixes. Removed unused format_injection_with_workspace. + +--- + +## Chapters + +### 1. Work +*Agent: default* + +- Widen DM filter rather than restructure — add pass-through for empty targets (presence), 'thread' synthetic targets, dm_/conv_ prefixed conversation IDs. Also removed dead code: format_injection_with_workspace import and function.: Widen DM filter rather than restructure — add pass-through for empty targets (presence), 'thread' synthetic targets, dm_/conv_ prefixed conversation IDs. Also removed dead code: format_injection_with_workspace import and function. +- Expanded DM filter to allow empty targets (presence), thread synthetic target, and dm_/conv_ prefixed conversation_id fallbacks. Removed unused format_injection_with_workspace function and import.: Expanded DM filter to allow empty targets (presence), thread synthetic target, and dm_/conv_ prefixed conversation_id fallbacks. Removed unused format_injection_with_workspace function and import. diff --git a/.trajectories/index.json b/.trajectories/index.json index 519d85fbf..7de0a909e 100644 --- a/.trajectories/index.json +++ b/.trajectories/index.json @@ -1,6 +1,6 @@ { "version": 1, - "lastUpdated": "2026-03-25T09:28:53.988Z", + "lastUpdated": "2026-03-25T16:29:26.213Z", "trajectories": { "traj_1b1dj40sl6jl": { "title": "Revert aggressive retry logic in relay-pty-orchestrator", @@ -856,6 +856,13 @@ "startedAt": "2026-03-25T09:28:08.884Z", "completedAt": "2026-03-25T09:28:53.882Z", "path": "/Users/khaliqgant/Projects/AgentWorkforce/relay/.trajectories/completed/2026-03/traj_1qnnaojcl0w6.json" + }, + "traj_hn0583gzi86w": { + "title": "Fix DM routing filter in wrap.rs — allow thread replies, presence events, and conversation_id targets", + "status": "completed", + "startedAt": "2026-03-25T16:25:02.609Z", + "completedAt": "2026-03-25T16:29:26.110Z", + "path": "/Users/khaliqgant/Projects/Agent Workforce/relay/.trajectories/completed/2026-03/traj_hn0583gzi86w.json" } } } \ No newline at end of file