fix: make acceptance timeline dedupe robust
This commit is contained in:
@ -258,7 +258,10 @@ describe('buildTaskTimelineCards', () => {
|
|||||||
actor_id: 'task-system',
|
actor_id: 'task-system',
|
||||||
actor_name: 'Task System',
|
actor_name: 'Task System',
|
||||||
text: '可以',
|
text: '可以',
|
||||||
created_at: '2026-05-26T10:05:00.000Z',
|
created_at: '2026-05-26T10:05:02.000Z',
|
||||||
|
metadata: {
|
||||||
|
acceptance_type: 'accept',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -168,6 +168,10 @@ function feedbackSummary(feedback: Record<string, unknown>): string | undefined
|
|||||||
return firstString(feedback.comment, feedback.summary, feedback.acceptance_type);
|
return firstString(feedback.comment, feedback.summary, feedback.acceptance_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function acceptanceTypeFromRecord(record: Record<string, unknown> | undefined): string | null {
|
||||||
|
return firstString(record?.acceptance_type, record?.feedback_type)?.toLowerCase() ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
function resultSummary(task: BackendTask): string | undefined {
|
function resultSummary(task: BackendTask): string | undefined {
|
||||||
return firstString(
|
return firstString(
|
||||||
task.metadata?.result_summary,
|
task.metadata?.result_summary,
|
||||||
@ -209,8 +213,29 @@ function compareCardsByCreatedAt(
|
|||||||
return aTime - bTime || a.index - b.index;
|
return aTime - bTime || a.index - b.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
function acceptanceKey(runId: string | null | undefined, createdAt: string): string {
|
type AcceptanceEventIdentity = {
|
||||||
return `${runId ?? ''}:${createdAt}`;
|
runId: string | null;
|
||||||
|
acceptanceType: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function isCoveredByAcceptanceEvent(
|
||||||
|
feedback: Record<string, unknown>,
|
||||||
|
acceptanceEvents: AcceptanceEventIdentity[],
|
||||||
|
): boolean {
|
||||||
|
const feedbackType = acceptanceTypeFromRecord(feedback);
|
||||||
|
if (!feedbackType) return false;
|
||||||
|
|
||||||
|
const feedbackRunId = firstString(feedback.run_id) ?? null;
|
||||||
|
const matchingTypeEvents = acceptanceEvents.filter((event) => event.acceptanceType === feedbackType);
|
||||||
|
|
||||||
|
if (feedbackRunId) {
|
||||||
|
return (
|
||||||
|
matchingTypeEvents.some((event) => event.runId === feedbackRunId) ||
|
||||||
|
(matchingTypeEvents.length === 1 && !matchingTypeEvents[0].runId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingTypeEvents.length === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildTaskTimelineCards(input: BuildTaskTimelineCardsInput): TaskTimelineCard[] {
|
export function buildTaskTimelineCards(input: BuildTaskTimelineCardsInput): TaskTimelineCard[] {
|
||||||
@ -220,7 +245,7 @@ export function buildTaskTimelineCards(input: BuildTaskTimelineCardsInput): Task
|
|||||||
const processArtifacts = input.processArtifacts ?? task.process_artifacts ?? [];
|
const processArtifacts = input.processArtifacts ?? task.process_artifacts ?? [];
|
||||||
const runsById = buildRunMap(processRuns);
|
const runsById = buildRunMap(processRuns);
|
||||||
const runsWithProgressEvents = new Set<string>();
|
const runsWithProgressEvents = new Set<string>();
|
||||||
const acceptanceEventKeys = new Set<string>();
|
const acceptanceEvents: AcceptanceEventIdentity[] = [];
|
||||||
let hasResultEventCard = false;
|
let hasResultEventCard = false;
|
||||||
const cards: TaskTimelineCard[] = [
|
const cards: TaskTimelineCard[] = [
|
||||||
{
|
{
|
||||||
@ -246,7 +271,10 @@ export function buildTaskTimelineCards(input: BuildTaskTimelineCardsInput): Task
|
|||||||
hasResultEventCard = true;
|
hasResultEventCard = true;
|
||||||
}
|
}
|
||||||
if (type === 'acceptance') {
|
if (type === 'acceptance') {
|
||||||
acceptanceEventKeys.add(acceptanceKey(event.run_id, event.created_at));
|
acceptanceEvents.push({
|
||||||
|
runId: firstString(event.run_id) ?? null,
|
||||||
|
acceptanceType: acceptanceTypeFromRecord(event.metadata),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cards.push({
|
cards.push({
|
||||||
@ -322,7 +350,7 @@ export function buildTaskTimelineCards(input: BuildTaskTimelineCardsInput): Task
|
|||||||
const feedback = task.feedback[index];
|
const feedback = task.feedback[index];
|
||||||
const runId = firstString(feedback.run_id) ?? null;
|
const runId = firstString(feedback.run_id) ?? null;
|
||||||
const createdAt = feedbackCreatedAt(feedback, task);
|
const createdAt = feedbackCreatedAt(feedback, task);
|
||||||
if (acceptanceEventKeys.has(acceptanceKey(runId, createdAt))) continue;
|
if (isCoveredByAcceptanceEvent(feedback, acceptanceEvents)) continue;
|
||||||
|
|
||||||
cards.push({
|
cards.push({
|
||||||
id: `${task.task_id}:acceptance:${index}`,
|
id: `${task.task_id}:acceptance:${index}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user