fix(team): hide review pickup escalation rows

This commit is contained in:
777genius 2026-05-09 16:01:20 +03:00
parent fa829f92c8
commit 5d3ec8a8bd
5 changed files with 92 additions and 12 deletions

View file

@ -287,29 +287,42 @@ function buildMemberWorkSyncReviewPickupEscalationText(input: {
}): string {
const taskLines = input.taskRefs.length
? input.taskRefs
.map(
(taskRef) => `- ${taskRef.displayId ?? taskRef.taskId.slice(0, 8)} (${taskRef.taskId})`
)
.map((taskRef) => `- ${taskRef.displayId ?? taskRef.taskId.slice(0, 8)}`)
.join('\n')
: '- No task refs recorded';
const diagnostics = [...new Set(input.diagnostics ?? [])].filter(Boolean);
const reasonText = describeMemberWorkSyncReviewPickupEscalationReason(input.reason);
return [
'Review pickup still pending in member work-sync.',
'Review pickup needs lead attention.',
'',
`Reviewer: ${input.memberName}`,
`Reason: ${input.reason}`,
reasonText,
'',
'Tasks:',
taskLines,
'',
'No review_start, review_approve, or review_request_changes was recorded for the current review request after the member correction path.',
'No review_start, review_approve, or review_request_changes was recorded for the current review request.',
'Consider reassigning the reviewer or sending a direct instruction.',
diagnostics.length ? `Diagnostics: ${diagnostics.join(', ')}` : '',
]
.filter(Boolean)
.join('\n');
}
function describeMemberWorkSyncReviewPickupEscalationReason(reason: string): string {
if (reason.startsWith('provider_not_supported:')) {
return 'Direct review-pickup wake is not available for this member runtime, so the lead needs to handle the stuck review.';
}
if (reason === 'review_pickup_already_delivered_still_stuck') {
return 'A review-pickup reminder was delivered, but the review is still waiting for a review tool action.';
}
if (reason === 'review_pickup_delivery_failed_still_stuck') {
return 'The review-pickup reminder could not be delivered reliably, and the review is still waiting.';
}
if (reason.includes('delivery_port_unavailable')) {
return 'No reliable review-pickup delivery path is available for this member runtime.';
}
return 'The current review request is still waiting for explicit review pickup.';
}
async function createOpenCodeRuntimeAdapterRegistry(
reportProgress: (phase: string, message: string) => void = () => undefined
): Promise<TeamRuntimeAdapterRegistry> {

View file

@ -24,7 +24,10 @@ import { filterTeamMessages } from '@renderer/utils/teamMessageFiltering';
import { toMessageKey } from '@renderer/utils/teamMessageKey';
import { shouldExcludeInboxTextFromReplyCandidates } from '@shared/utils/idleNotificationSemantics';
import { isLeadMember } from '@shared/utils/leadDetection';
import { isTaskStallRemediationMessage } from '@shared/utils/teamAutomationMessages';
import {
isReviewPickupEscalationMessage,
isTaskStallRemediationMessage,
} from '@shared/utils/teamAutomationMessages';
import {
CheckCheck,
ChevronsDownUp,
@ -603,6 +606,7 @@ export const MessagesPanel = memo(function MessagesPanel({
(m) =>
m.messageKind !== 'task_comment_notification' &&
!isTaskStallRemediationMessage(m) &&
!isReviewPickupEscalationMessage(m) &&
!shouldExcludeInboxTextFromReplyCandidates(typeof m.text === 'string' ? m.text : '')
),
[effectiveMessages]

View file

@ -4,7 +4,10 @@ import {
} from '@renderer/utils/bootstrapPromptSanitizer';
import { shouldKeepIdleMessageInActivityWhenNoiseHidden } from '@renderer/utils/idleNotificationSemantics';
import { isInboxNoiseMessage } from '@shared/utils/inboxNoise';
import { isTaskStallRemediationMessage } from '@shared/utils/teamAutomationMessages';
import {
isReviewPickupEscalationMessage,
isTaskStallRemediationMessage,
} from '@shared/utils/teamAutomationMessages';
import { isTeamInternalControlMessageEnvelope } from '@shared/utils/teamInternalControlMessages';
import type { InboxMessage } from '@shared/types';
@ -133,6 +136,7 @@ export function filterTeamMessages(
(m) =>
m.messageKind !== 'task_comment_notification' &&
(includeAutomationEvents || !isTaskStallRemediationMessage(m)) &&
!isReviewPickupEscalationMessage(m) &&
!isTeamInternalControlMessageEnvelope(m)
);
if (timeWindow) {

View file

@ -2,15 +2,26 @@ import type { InboxMessage } from '@shared/types';
type AutomationMessageLike = Pick<InboxMessage, 'from' | 'messageId' | 'messageKind' | 'source'>;
function getMessageId(message: AutomationMessageLike): string {
return typeof message.messageId === 'string' ? message.messageId.trim() : '';
}
export function isTaskStallRemediationMessage(message: AutomationMessageLike): boolean {
if (message.messageKind === 'task_stall_remediation') {
return true;
}
const messageId = typeof message.messageId === 'string' ? message.messageId.trim() : '';
return (
message.source === 'system_notification' &&
message.from === 'system' &&
messageId.startsWith('task-stall:')
getMessageId(message).startsWith('task-stall:')
);
}
export function isReviewPickupEscalationMessage(message: AutomationMessageLike): boolean {
return (
message.source === 'system_notification' &&
message.from === 'system' &&
getMessageId(message).startsWith('member-work-sync-review-pickup-escalation:')
);
}

View file

@ -585,6 +585,31 @@ Messages:
expect(result.map((message) => message.messageId)).toEqual(['msg-2']);
});
it('hides review pickup escalation automation rows from conversational message counts by default', () => {
const messages = [
makeMessage({
messageId: 'member-work-sync-review-pickup-escalation:abc123',
from: 'system',
to: 'lead',
source: 'system_notification',
summary: 'Review pickup still pending',
text: 'Review pickup needs lead attention.\n\nReviewer: tom',
}),
makeMessage({
messageId: 'msg-2',
text: 'Visible message',
}),
];
const result = filterTeamMessages(messages, {
timeWindow: null,
filter: { from: new Set(), to: new Set(), showNoise: true },
searchQuery: '',
});
expect(result.map((message) => message.messageId)).toEqual(['msg-2']);
});
it('can include task stall remediation automation rows for the activity timeline', () => {
const messages = [
makeMessage({
@ -608,4 +633,27 @@ Messages:
'task-stall:demo:task-a:legacy-epoch',
]);
});
it('keeps review pickup escalation hidden even when regular automation rows are included', () => {
const messages = [
makeMessage({
messageId: 'member-work-sync-review-pickup-escalation:abc123',
from: 'system',
to: 'lead',
source: 'system_notification',
summary: 'Review pickup still pending',
text: 'Review pickup needs lead attention.\n\nReviewer: tom',
}),
];
const result = filterTeamMessages(messages, {
includeAutomationEvents: true,
timeWindow: null,
filter: { from: new Set(), to: new Set(), showNoise: true },
searchQuery: '',
});
expect(result).toEqual([]);
});
});