From c963c8a409e7b35022581a402bf7c682c86e9906 Mon Sep 17 00:00:00 2001 From: iliya Date: Thu, 5 Mar 2026 18:20:25 +0200 Subject: [PATCH] feat: enhance DM handling in teams.ts with structured message formatting - Introduced structured message formatting for direct messages to improve clarity for recipients. - Updated message delivery logic to include additional context for non-lead recipients. - Retained AGENT_BLOCK constants import for better organization and readability. --- src/main/ipc/teams.ts | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/ipc/teams.ts b/src/main/ipc/teams.ts index 8ba27529..5b6edb40 100644 --- a/src/main/ipc/teams.ts +++ b/src/main/ipc/teams.ts @@ -56,6 +56,7 @@ import { TEAM_DELETE_TASK_ATTACHMENT, // eslint-disable-next-line boundaries/element-types -- IPC channel constants are shared between main and preload by design } from '@preload/constants/ipcChannels'; +import { AGENT_BLOCK_CLOSE, AGENT_BLOCK_OPEN } from '@shared/constants/agentBlocks'; import { KANBAN_COLUMN_IDS } from '@shared/constants/kanban'; import { createLogger } from '@shared/utils/logger'; import { isRateLimitMessage } from '@shared/utils/rateLimitDetector'; @@ -74,7 +75,6 @@ import { validateTeammateName, validateTeamName, } from './guards'; -import { AGENT_BLOCK_CLOSE, AGENT_BLOCK_OPEN } from '@shared/constants/agentBlocks'; /** Track rate limit message keys already notified to avoid duplicate OS notifications across refreshes. */ const notifiedRateLimitKeys = new Set(); @@ -1016,13 +1016,35 @@ async function handleSendMessage( } // Inbox path: offline lead or regular members (no attachment support) + const baseText = payload.text!.trim(); + const memberDeliveryText = isLeadRecipient + ? baseText + : [ + baseText, + '', + AGENT_BLOCK_OPEN, + 'You received a direct message from the human user via the UI.', + 'Please reply back to recipient "user" with a short, human-readable answer.', + 'If you cannot respond now, reply with a brief status (e.g. "Busy, will reply later").', + AGENT_BLOCK_CLOSE, + ].join('\n'); const result = await getTeamDataService().sendMessage(tn, { member: memberName, - text: payload.text!, + text: memberDeliveryText, summary: payload.summary, from: payload.from, }); + // Best-effort: if team is alive and recipient is a teammate (not lead), + // also forward via the live lead process so in-process teammates receive it. + if (!isLeadRecipient && isAlive) { + try { + await provisioning.forwardUserDmToTeammate(tn, memberName, baseText, payload.summary); + } catch (e: unknown) { + logger.warn(`Failed to forward user DM to teammate "${memberName}" via lead: ${String(e)}`); + } + } + // Best-effort relay for lead via inbox if (isLeadRecipient && isAlive) { void provisioning