Files
Agent-System/web/src/lib/taskPhaseReplay.ts
T

46 lines
1.5 KiB
TypeScript

import type { ChatMessage, PhaseEvent } from '../types/workbench';
const TERMINAL_REPLAY_STATUSES = new Set([
'completed',
'failed',
'quality_failed',
'cancelled',
'pending_author_confirmation',
'blocked_pending_governance',
]);
/** 刷新后需要从 task_run_events 重建进度条的气泡。已有步骤或快照则不再拉。 */
export function messageNeedsPhaseReplay(
message: Pick<
ChatMessage,
'role' | 'taskRunId' | 'phaseEvents' | 'phaseSnapshot' | 'status' | 'errorInfo'
>,
): boolean {
if (message.role !== 'assistant' || !message.taskRunId) return false;
if (message.phaseEvents && message.phaseEvents.length > 0) return false;
if (message.phaseSnapshot?.steps && message.phaseSnapshot.steps.length > 0) return false;
if (message.status === 'streaming_status') return true;
if (message.errorInfo?.code === 'TASK_INTERRUPTED') return true;
// 存量终态消息:无 snapshot、无步骤时扩面重放,避免卡片退化成纯文本。
if (message.status && TERMINAL_REPLAY_STATUSES.has(message.status)) return true;
return false;
}
export function phaseReplayKey(
messages: Pick<
ChatMessage,
'id' | 'role' | 'taskRunId' | 'phaseEvents' | 'phaseSnapshot' | 'status' | 'errorInfo'
>[],
): string {
return messages
.filter(messageNeedsPhaseReplay)
.map((message) => `${message.id}:${message.taskRunId}:${message.status}`)
.sort()
.join('|');
}
export type PhaseReplayCacheEntry = {
events: PhaseEvent[];
label?: string;
};