feat(AgentAudit): 添加进度日志功能支持
添加 progress 日志类型,支持通过 progressKey 更新或添加进度日志 在日志组件中增加进度日志的样式和显示 处理进度消息的匹配和更新逻辑,避免重复添加日志
This commit is contained in:
parent
18a91f25b2
commit
2bba972272
|
|
@ -24,6 +24,7 @@ const LOG_TYPE_LABELS: Record<string, string> = {
|
|||
info: 'INFO',
|
||||
error: 'ERROR',
|
||||
user: 'USER',
|
||||
progress: 'PROGRESS',
|
||||
};
|
||||
|
||||
// Helper to format title (remove emojis and clean up)
|
||||
|
|
@ -73,6 +74,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
|
|||
const isFinding = item.type === 'finding';
|
||||
const isError = item.type === 'error';
|
||||
const isInfo = item.type === 'info';
|
||||
const isProgress = item.type === 'progress';
|
||||
const showContent = isThinking || isExpanded;
|
||||
const isCollapsible = !isThinking && item.content;
|
||||
|
||||
|
|
@ -124,6 +126,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
|
|||
${isFinding ? 'bg-rose-500/25 text-rose-300' : ''}
|
||||
${isError ? 'bg-red-500/25 text-red-300' : ''}
|
||||
${isInfo ? 'bg-slate-500/25 text-slate-300' : ''}
|
||||
${isProgress ? 'bg-cyan-500/25 text-cyan-300' : ''}
|
||||
${item.type === 'dispatch' ? 'bg-sky-500/25 text-sky-300' : ''}
|
||||
${item.type === 'phase' ? 'bg-teal-500/25 text-teal-300' : ''}
|
||||
${item.type === 'user' ? 'bg-indigo-500/25 text-indigo-300' : ''}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,11 @@ export const LOG_TYPE_CONFIG: Record<string, {
|
|||
borderColor: "border-l-indigo-500",
|
||||
bgColor: "bg-indigo-500/10"
|
||||
},
|
||||
progress: {
|
||||
icon: React.createElement(Loader2, { className: "w-4 h-4 text-cyan-400 animate-spin" }),
|
||||
borderColor: "border-l-cyan-500",
|
||||
bgColor: "bg-cyan-500/10"
|
||||
},
|
||||
};
|
||||
|
||||
// ============ Agent Status Configurations ============
|
||||
|
|
|
|||
|
|
@ -101,6 +101,34 @@ function agentAuditReducer(state: AgentAuditState, action: AgentAuditAction): Ag
|
|||
return { ...state, logs: updatedLogs };
|
||||
}
|
||||
|
||||
case 'UPDATE_OR_ADD_PROGRESS_LOG': {
|
||||
const { progressKey, title, agentName } = action.payload;
|
||||
// 查找是否已存在相同 progressKey 的进度日志
|
||||
const existingIndex = state.logs.findIndex(
|
||||
log => log.type === 'progress' && log.progressKey === progressKey
|
||||
);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
// 更新现有日志的 title 和 time
|
||||
const updatedLogs = [...state.logs];
|
||||
updatedLogs[existingIndex] = {
|
||||
...updatedLogs[existingIndex],
|
||||
title,
|
||||
time: new Date().toLocaleTimeString('en-US', { hour12: false }),
|
||||
};
|
||||
return { ...state, logs: updatedLogs };
|
||||
} else {
|
||||
// 添加新的进度日志
|
||||
const newLog = createLogItem({
|
||||
type: 'progress',
|
||||
title,
|
||||
progressKey,
|
||||
agentName,
|
||||
});
|
||||
return { ...state, logs: [...state.logs, newLog] };
|
||||
}
|
||||
}
|
||||
|
||||
case 'SELECT_AGENT':
|
||||
return {
|
||||
...state,
|
||||
|
|
|
|||
|
|
@ -317,8 +317,27 @@ function AgentAuditPageContent() {
|
|||
|
||||
// 进度事件
|
||||
case 'progress':
|
||||
// 进度事件可以选择显示或跳过
|
||||
// 进度事件使用 UPDATE_OR_ADD_PROGRESS_LOG 来更新而不是添加
|
||||
if (event.message) {
|
||||
const progressPatterns: { pattern: RegExp; key: string }[] = [
|
||||
{ pattern: /索引进度[::]?\s*\d+\/\d+/, key: 'index_progress' },
|
||||
{ pattern: /克隆进度[::]?\s*\d+%/, key: 'clone_progress' },
|
||||
{ pattern: /下载进度[::]?\s*\d+%/, key: 'download_progress' },
|
||||
{ pattern: /上传进度[::]?\s*\d+%/, key: 'upload_progress' },
|
||||
{ pattern: /扫描进度[::]?\s*\d+/, key: 'scan_progress' },
|
||||
{ pattern: /分析进度[::]?\s*\d+/, key: 'analyze_progress' },
|
||||
];
|
||||
const matchedProgress = progressPatterns.find(p => p.pattern.test(event.message || ''));
|
||||
if (matchedProgress) {
|
||||
dispatch({
|
||||
type: 'UPDATE_OR_ADD_PROGRESS_LOG',
|
||||
payload: {
|
||||
progressKey: matchedProgress.key,
|
||||
title: event.message,
|
||||
agentName,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: 'ADD_LOG',
|
||||
payload: {
|
||||
|
|
@ -327,6 +346,7 @@ function AgentAuditPageContent() {
|
|||
agentName,
|
||||
}
|
||||
});
|
||||
}
|
||||
processedCount++;
|
||||
}
|
||||
break;
|
||||
|
|
@ -335,17 +355,40 @@ function AgentAuditPageContent() {
|
|||
case 'info':
|
||||
case 'complete':
|
||||
case 'error':
|
||||
case 'warning':
|
||||
case 'warning': {
|
||||
const message = event.message || `${event.event_type}`;
|
||||
// 检测进度类型消息
|
||||
const progressPatterns: { pattern: RegExp; key: string }[] = [
|
||||
{ pattern: /索引进度[::]?\s*\d+\/\d+/, key: 'index_progress' },
|
||||
{ pattern: /克隆进度[::]?\s*\d+%/, key: 'clone_progress' },
|
||||
{ pattern: /下载进度[::]?\s*\d+%/, key: 'download_progress' },
|
||||
{ pattern: /上传进度[::]?\s*\d+%/, key: 'upload_progress' },
|
||||
{ pattern: /扫描进度[::]?\s*\d+/, key: 'scan_progress' },
|
||||
{ pattern: /分析进度[::]?\s*\d+/, key: 'analyze_progress' },
|
||||
];
|
||||
const matchedProgress = progressPatterns.find(p => p.pattern.test(message));
|
||||
if (matchedProgress) {
|
||||
dispatch({
|
||||
type: 'UPDATE_OR_ADD_PROGRESS_LOG',
|
||||
payload: {
|
||||
progressKey: matchedProgress.key,
|
||||
title: message,
|
||||
agentName,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: 'ADD_LOG',
|
||||
payload: {
|
||||
type: event.event_type === 'error' ? 'error' : 'info',
|
||||
title: event.message || `${event.event_type}`,
|
||||
title: message,
|
||||
agentName,
|
||||
}
|
||||
});
|
||||
}
|
||||
processedCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
// 跳过 thinking_token 等高频事件(它们不会被保存到数据库)
|
||||
case 'thinking_token':
|
||||
|
|
@ -410,14 +453,41 @@ function AgentAuditPageContent() {
|
|||
// 🔥 处理 info、warning、error 类型事件(克隆进度、索引进度等)
|
||||
const infoEvents = ['info', 'warning', 'error', 'progress'];
|
||||
if (infoEvents.includes(event.type)) {
|
||||
const message = event.message || event.type;
|
||||
|
||||
// 🔥 检测进度类型消息,使用更新而不是添加
|
||||
const progressPatterns: { pattern: RegExp; key: string }[] = [
|
||||
{ pattern: /索引进度[::]?\s*\d+\/\d+/, key: 'index_progress' },
|
||||
{ pattern: /克隆进度[::]?\s*\d+%/, key: 'clone_progress' },
|
||||
{ pattern: /下载进度[::]?\s*\d+%/, key: 'download_progress' },
|
||||
{ pattern: /上传进度[::]?\s*\d+%/, key: 'upload_progress' },
|
||||
{ pattern: /扫描进度[::]?\s*\d+/, key: 'scan_progress' },
|
||||
{ pattern: /分析进度[::]?\s*\d+/, key: 'analyze_progress' },
|
||||
];
|
||||
|
||||
const matchedProgress = progressPatterns.find(p => p.pattern.test(message));
|
||||
|
||||
if (matchedProgress) {
|
||||
// 使用 UPDATE_OR_ADD_PROGRESS_LOG 来更新进度而不是添加新日志
|
||||
dispatch({
|
||||
type: 'UPDATE_OR_ADD_PROGRESS_LOG',
|
||||
payload: {
|
||||
progressKey: matchedProgress.key,
|
||||
title: message,
|
||||
agentName: getCurrentAgentName() || undefined,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 非进度消息正常添加
|
||||
dispatch({
|
||||
type: 'ADD_LOG',
|
||||
payload: {
|
||||
type: event.type === 'error' ? 'error' : 'info',
|
||||
title: event.message || event.type,
|
||||
title: message,
|
||||
agentName: getCurrentAgentName() || undefined,
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ export type LogType =
|
|||
| 'info'
|
||||
| 'error'
|
||||
| 'user'
|
||||
| 'dispatch';
|
||||
| 'dispatch'
|
||||
| 'progress';
|
||||
|
||||
export type ToolStatus = 'running' | 'completed' | 'failed';
|
||||
|
||||
|
|
@ -33,6 +34,7 @@ export interface LogItem {
|
|||
};
|
||||
severity?: string;
|
||||
agentName?: string;
|
||||
progressKey?: string; // 用于标识进度日志的唯一键,如 "index_progress"
|
||||
}
|
||||
|
||||
// ============ Connection Types ============
|
||||
|
|
@ -76,6 +78,7 @@ export type AgentAuditAction =
|
|||
| { type: 'SET_LOGS'; payload: LogItem[] }
|
||||
| { type: 'ADD_LOG'; payload: Omit<LogItem, 'id' | 'time'> & { id?: string } }
|
||||
| { type: 'UPDATE_LOG'; payload: { id: string; updates: Partial<LogItem> } }
|
||||
| { type: 'UPDATE_OR_ADD_PROGRESS_LOG'; payload: { progressKey: string; title: string; agentName?: string } }
|
||||
| { type: 'COMPLETE_TOOL_LOG'; payload: { toolName: string; output: string; duration: number } }
|
||||
| { type: 'REMOVE_LOG'; payload: string }
|
||||
| { type: 'SELECT_AGENT'; payload: string | null }
|
||||
|
|
|
|||
Loading…
Reference in New Issue