From cbd09199b375d5561812f807544538cec91a73d7 Mon Sep 17 00:00:00 2001 From: iliya Date: Sun, 15 Mar 2026 11:43:29 +0200 Subject: [PATCH] feat: enhance task assignment messaging and improve action mode instructions - Updated the task assignment message to emphasize the importance of starting tasks promptly, with improved formatting for clarity. - Revised action mode instructions for the 'delegate' mode to provide clearer guidance on delegation responsibilities and expectations, including the creation of investigation tasks for ambiguous requests. - Added new protocols in TeamProvisioningService to clarify ownership and task refinement processes during investigations, ensuring better task management and accountability. --- agent-teams-controller/src/internal/tasks.js | 3 +- .../services/team/TeamProvisioningService.ts | 12 +++- .../services/team/actionModeInstructions.ts | 6 +- src/renderer/components/team/TeamListView.tsx | 66 +++++++++++++++---- .../team/activity/activityMessageContext.ts | 7 +- .../members/SubagentRecentMessagesPreview.tsx | 3 +- 6 files changed, 72 insertions(+), 25 deletions(-) diff --git a/agent-teams-controller/src/internal/tasks.js b/agent-teams-controller/src/internal/tasks.js index 846373fd..d16041d0 100644 --- a/agent-teams-controller/src/internal/tasks.js +++ b/agent-teams-controller/src/internal/tasks.js @@ -40,7 +40,8 @@ function buildAssignmentMessage(context, task, options = {}) { const taskLabel = `#${task.displayId || task.id}`; const lines = [ `New task assigned to you: ${taskLabel} "${task.subject}".`, - `If you are not currently working on another task, start this one now. If you are busy, start it as soon as your current task is finished.`, + ``, + `*If you are not currently working on another task, start this one now. If you are busy, start it as soon as your current task is finished.*`, ]; if (description) { diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index 3b56d3e0..0a6dea3c 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -678,6 +678,11 @@ function buildTaskStatusProtocol(teamName: string): string { - If you are the one doing the implementation/fixes and the owner is missing or someone else, run task_set_owner to yourself immediately before task_start. - Then run task_start only when you truly begin. - If you complete fixes for a needsFix task, mark it completed and then send it back through review_request when ready for another review pass. +15. INVESTIGATION / TASK REFINEMENT: + - If the lead assigns you a broad investigation/triage task, you own the code inspection and scope discovery for that work. + - If you discover distinct substantial follow-up work that should be tracked separately, create the follow-up board task(s) yourself with task_create, assign them to the actual owner, and link them with related or blockedBy when useful. + - If you plan to execute one of those follow-up tasks yourself, make sure the owner is set to you before you start it. + - Record the new task refs in a task comment on the original investigation task so the lead can see the decomposition. Failure to follow this protocol means the task board will show incorrect status.`); } @@ -830,6 +835,9 @@ Constraints: - Keep the task board high-signal: avoid creating tasks for trivial micro-items. - Use the team task board for assigned/substantial work. - DELEGATION-FIRST (behavior rule for ALL future turns): When "user" gives you work, your top priority is to (a) decompose into tasks, (b) create tasks on the team board, (c) assign them to teammates, and (d) SendMessage "user" a short confirmation (task IDs + owners). Do NOT start implementing yourself unless the team is truly in SOLO MODE (no teammates). +- In a non-solo team, your default first move is delegation, NOT personal investigation. Do NOT read/search the codebase, inspect files, or do root-cause research yourself just to figure out ownership or scope before delegating. +- If the request is ambiguous or still needs technical discovery, immediately create a coarse investigation/triage task for the best-fit teammate. That teammate owns the code inspection, scope refinement, and creation of any follow-up tasks needed for execution. +- Only do lead-side research first if the human explicitly asked YOU for analysis/planning, or if there is genuinely no appropriate teammate to own the investigation. - TaskCreate is optional for private planning only; do NOT use it for team-board tasks. - When messaging "user" (the human): NEVER mention internal MCP tools, scripts, CLI commands, or file paths under ~/.claude/. The user sees messages in the UI — write plain human language. If a task needs a status update, do it yourself via the board MCP tools; never ask the user to run a command.${soloConstraint} @@ -993,7 +1001,9 @@ function buildProvisioningPrompt(request: TeamCreateRequest): string { - Exception: only if the team is truly SOLO (no teammates) may you execute tasks yourself. This is NOT the case here. - Decompose the request into a small set of clear, outcome-based tasks (prefer fewer, broader tasks over many micro-tasks). - Assign each created task to an appropriate teammate as owner (NOT to yourself), based on role/workflow and current load. - - If ownership is unclear, pick the best default owner and note assumptions in the task description or a task comment. + - If ownership or scope is unclear, do NOT block on researching the code yourself first. + Pick the best default owner, create an investigation/triage task for that teammate immediately, and note assumptions in the task description or a task comment. + That teammate should inspect the codebase, refine scope, and create follow-up tasks if needed. - If that teammate already has another in_progress task, create/keep the new task in pending/TODO. Do NOT mark it in_progress for them yet. - Avoid duplicate notifications for the same assignment (one message per member per topic is enough). - When tasks have natural ordering (e.g. setup -> implementation -> testing), use blockedBy relationships. diff --git a/src/main/services/team/actionModeInstructions.ts b/src/main/services/team/actionModeInstructions.ts index 867c3bfd..ce6f6869 100644 --- a/src/main/services/team/actionModeInstructions.ts +++ b/src/main/services/team/actionModeInstructions.ts @@ -18,7 +18,9 @@ const ACTION_MODE_BLOCKS: Record = { delegate: [ 'TURN ACTION MODE: DELEGATE', '- This turn is STRICTLY delegation/orchestration mode.', - '- If you are the team lead, decompose the work, create/assign tasks, coordinate teammates, and monitor progress.', + '- If you are the team lead, stay at orchestration level: decompose the work, create/assign tasks fast, delegate triage/research to the best teammate, and monitor progress.', + '- In this mode, do NOT inspect code, do root-cause research, or spend time narrowing scope yourself before delegating unless the human explicitly asked you for analysis/planning instead of delegation.', + '- If the request is underspecified, create a coarse investigation/triage task for the most relevant teammate immediately; that teammate should inspect the codebase, refine scope, and create follow-up tasks if needed.', '- FORBIDDEN: implementing the work yourself, editing files yourself, running state-changing/code-changing commands yourself, or taking direct execution ownership unless you are truly in SOLO MODE.', '- If you are not the lead or no delegation target exists, do not execute the work yourself; explain the limitation briefly and request a different mode or a lead handoff.', ], @@ -34,7 +36,7 @@ export function buildActionModeProtocol(): string { '- Modes:', ' - DO: Full execution mode. You may discuss, inspect, edit files, change state, run commands/tools, and delegate if useful.', ' - ASK: Strict read-only conversation mode. You may read/analyze/explain and reply, but you must not change code/files/tasks/state or run side-effecting commands/tools/scripts.', - ' - DELEGATE: Strict orchestration mode for leads. Delegate the work to teammates and coordinate it, but do not implement it yourself unless you are truly in SOLO MODE.', + ' - DELEGATE: Strict orchestration mode for leads. Delegate the work and any needed investigation to teammates, coordinate it, and do not implement or personally research it yourself unless you are truly in SOLO MODE.', ].join('\n'); } diff --git a/src/renderer/components/team/TeamListView.tsx b/src/renderer/components/team/TeamListView.tsx index da404d6f..8ac8da36 100644 --- a/src/renderer/components/team/TeamListView.tsx +++ b/src/renderer/components/team/TeamListView.tsx @@ -222,6 +222,7 @@ export const TeamListView = (): React.JSX.Element => { const { connectionMode, createTeam, + launchTeam, provisioningErrorByTeam, clearProvisioningError, provisioningRuns, @@ -232,6 +233,7 @@ export const TeamListView = (): React.JSX.Element => { useShallow((s) => ({ connectionMode: s.connectionMode, createTeam: s.createTeam, + launchTeam: s.launchTeam, provisioningErrorByTeam: s.provisioningErrorByTeam, clearProvisioningError: s.clearProvisioningError, provisioningRuns: s.provisioningRuns, @@ -502,6 +504,24 @@ export const TeamListView = (): React.JSX.Element => { } }, []); + const [launchingTeamName, setLaunchingTeamName] = useState(null); + const handleLaunchTeam = useCallback( + async (teamName: string, projectPath: string | undefined, e: React.MouseEvent) => { + e.stopPropagation(); + if (!projectPath) return; + setLaunchingTeamName(teamName); + try { + await launchTeam({ teamName, cwd: projectPath }); + openTeamTab(teamName, projectPath); + } catch (err) { + console.error('Failed to launch team:', err); + } finally { + setLaunchingTeamName(null); + } + }, + [launchTeam, openTeamTab] + ); + useEffect(() => { if (!electronMode) { return; @@ -720,8 +740,40 @@ export const TeamListView = (): React.JSX.Element => { {team.displayName} + {team.projectPath && + (() => { + const branch = branchByPath[normalizePath(team.projectPath)]; + if (!branch) return null; + return ( + + + {branch} + + ); + })()}
+ {status === 'offline' && team.projectPath && ( + + + + + + {launchingTeamName === team.teamName ? 'Launching…' : 'Launch team'} + + + )} {(status === 'active' || status === 'idle') && ( @@ -770,20 +822,6 @@ export const TeamListView = (): React.JSX.Element => {

{team.description || 'No description'}

- {team.projectPath && - (() => { - const branch = branchByPath[normalizePath(team.projectPath)]; - if (!branch) return null; - return ( - - - {branch} - - ); - })()}
{team.members && team.members.length > 0 ? ( diff --git a/src/renderer/components/team/activity/activityMessageContext.ts b/src/renderer/components/team/activity/activityMessageContext.ts index 98b96351..068eced6 100644 --- a/src/renderer/components/team/activity/activityMessageContext.ts +++ b/src/renderer/components/team/activity/activityMessageContext.ts @@ -37,12 +37,7 @@ export function buildMessageContext(members?: ResolvedTeamMember[]): MessageCont } } - const leadMember = members.find( - (m) => m.agentType === 'team-lead' || m.role?.toLowerCase().includes('lead') - ); - if (leadMember && memberInfo.has(leadMember.name)) { - memberInfo.set('user', { role: undefined, color: colorMap.get('user') }); - } + memberInfo.set('user', { role: undefined, color: colorMap.get('user') }); return { colorMap, localMemberNames, memberInfo }; } diff --git a/src/renderer/components/team/members/SubagentRecentMessagesPreview.tsx b/src/renderer/components/team/members/SubagentRecentMessagesPreview.tsx index 54bb3872..21d561d0 100644 --- a/src/renderer/components/team/members/SubagentRecentMessagesPreview.tsx +++ b/src/renderer/components/team/members/SubagentRecentMessagesPreview.tsx @@ -53,7 +53,8 @@ export const SubagentRecentMessagesPreview = ({ {messages.map((m, index) => (