From 6798c4b9e7ce10a55e3d1b06c6ab6511a185bbff Mon Sep 17 00:00:00 2001 From: iliya Date: Mon, 16 Mar 2026 17:36:23 +0200 Subject: [PATCH] feat: enhance team provisioning and message preview handling - Updated TeamProvisioningService to include subagent type in spawn messages for clarity. - Improved member registration checks to account for suffixed names, enhancing error handling. - Refactored SubagentRecentMessagesPreview to strip agent-only blocks from messages, improving display clarity. - Adjusted tests to reflect changes in message formatting and member provisioning logic. --- .../services/team/TeamProvisioningService.ts | 14 ++++++++++---- .../members/SubagentRecentMessagesPreview.tsx | 19 ++++++++++++++++--- test/main/ipc/teams.test.ts | 2 +- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index 894bf00e..be3c055a 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -35,7 +35,7 @@ import { isLeadAgentType, isLeadMember } from '@shared/utils/leadDetection'; import { createLogger } from '@shared/utils/logger'; import { formatTaskDisplayLabel } from '@shared/utils/taskIdentity'; import { parseAllTeammateMessages } from '@shared/utils/teammateMessageParser'; -import { createCliAutoSuffixNameGuard } from '@shared/utils/teamMemberName'; +import { createCliAutoSuffixNameGuard, parseNumericSuffixName } from '@shared/utils/teamMemberName'; import { extractToolPreview, formatToolSummaryFromCalls } from '@shared/utils/toolSummary'; import * as agentTeamsControllerModule from 'agent-teams-controller'; import { spawn, type ChildProcess } from 'child_process'; @@ -597,7 +597,7 @@ export function buildAddMemberSpawnMessage( if (!isMemberBriefingBootstrapEnabled()) { return ( `A new teammate "${member.name}"${roleHint} has been added to the team. ` + - `Please spawn them immediately using the Task tool with team_name="${teamName}" and name="${member.name}".${workflowHint}` + `Please spawn them immediately using the Task tool with team_name="${teamName}", name="${member.name}", and subagent_type="general-purpose".${workflowHint}` ); } @@ -4247,11 +4247,17 @@ export class TeamProvisioningService { // Flag any expected member not found in config.json (excluding the lead) for (const expected of run.expectedMembers) { + // Check exact name or CLI-suffixed variant (e.g., "alice-2" for "alice") if (registeredNames.has(expected)) continue; + const hasSuffixed = [...registeredNames].some((name) => { + const parsed = parseNumericSuffixName(name); + return parsed !== null && parsed.suffix >= 2 && parsed.base === expected; + }); + if (hasSuffixed) continue; - // Skip if already in a terminal status (e.g., previously set 'error') + // Skip if already in a terminal or positive status const current = run.memberSpawnStatuses.get(expected); - if (current?.status === 'error') continue; + if (current?.status === 'error' || current?.status === 'online') continue; logger.warn( `[${run.teamName}] Member "${expected}" not found in config.json members after provisioning` diff --git a/src/renderer/components/team/members/SubagentRecentMessagesPreview.tsx b/src/renderer/components/team/members/SubagentRecentMessagesPreview.tsx index 21d561d0..b4611407 100644 --- a/src/renderer/components/team/members/SubagentRecentMessagesPreview.tsx +++ b/src/renderer/components/team/members/SubagentRecentMessagesPreview.tsx @@ -1,7 +1,8 @@ -import { useState } from 'react'; +import { useMemo, useState } from 'react'; import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer'; import { displayMemberName } from '@renderer/utils/memberHelpers'; +import { stripAgentBlocks } from '@shared/constants/agentBlocks'; import { format } from 'date-fns'; import { ChevronDown, ChevronUp } from 'lucide-react'; @@ -39,7 +40,19 @@ export const SubagentRecentMessagesPreview = ({ }: SubagentRecentMessagesPreviewProps): React.JSX.Element | null => { const [expandedAll, setExpandedAll] = useState(false); - if (!messages.length) return null; + // Strip agent-only blocks from message content before display + const cleanMessages = useMemo( + () => + messages + .map((m) => { + const cleaned = stripAgentBlocks(m.content); + return cleaned !== m.content ? { ...m, content: cleaned } : m; + }) + .filter((m) => m.content.trim().length > 0), + [messages] + ); + + if (!cleanMessages.length) return null; return (
@@ -50,7 +63,7 @@ export const SubagentRecentMessagesPreview = ({
- {messages.map((m, index) => ( + {cleanMessages.map((m, index) => (
{ expect(result.success).toBe(true); expect(provisioningService.sendMessageToTeam).toHaveBeenCalledWith( 'my-team', - expect.stringContaining('Please spawn them immediately using the Task tool with team_name="my-team" and name="alice".') + expect.stringContaining('Please spawn them immediately using the Task tool with team_name="my-team", name="alice", and subagent_type="general-purpose".') ); expect(provisioningService.sendMessageToTeam).not.toHaveBeenCalledWith( 'my-team',