Add files via upload

This commit is contained in:
公明
2025-11-16 23:06:14 +08:00
committed by GitHub
parent a4df77fc13
commit 71b6c8aa2d
2 changed files with 170 additions and 16 deletions

View File

@@ -290,15 +290,43 @@ func (h *AgentHandler) AgentLoopStream(c *gin.Context) {
defer cancelWithCause(nil)
if _, err := h.tasks.StartTask(conversationID, req.Message, cancelWithCause); err != nil {
var errorMsg string
if errors.Is(err, ErrTaskAlreadyRunning) {
sendEvent("error", "当前会话已有任务正在执行,请先停止后再尝试。", map[string]interface{}{
errorMsg = "⚠️ 当前会话已有任务正在执行,请等待当前任务完成或点击「停止任务」按钮后再尝试。"
sendEvent("error", errorMsg, map[string]interface{}{
"conversationId": conversationID,
"errorType": "task_already_running",
})
} else {
sendEvent("error", "无法启动任务: "+err.Error(), map[string]interface{}{
errorMsg = "无法启动任务: " + err.Error()
sendEvent("error", errorMsg, map[string]interface{}{
"conversationId": conversationID,
"errorType": "task_start_failed",
})
}
// 更新助手消息内容并保存错误详情到数据库
if assistantMessageID != "" {
if _, updateErr := h.db.Exec(
"UPDATE messages SET content = ? WHERE id = ?",
errorMsg,
assistantMessageID,
); updateErr != nil {
h.logger.Warn("更新错误后的助手消息失败", zap.Error(updateErr))
}
// 保存错误详情到数据库
if err := h.db.AddProcessDetail(assistantMessageID, conversationID, "error", errorMsg, map[string]interface{}{
"errorType": func() string {
if errors.Is(err, ErrTaskAlreadyRunning) {
return "task_already_running"
}
return "task_start_failed"
}(),
}); err != nil {
h.logger.Warn("保存错误详情失败", zap.Error(err))
}
}
sendEvent("done", "", map[string]interface{}{
"conversationId": conversationID,
})

View File

@@ -478,15 +478,18 @@ function toggleProgressDetails(progressId) {
// 折叠所有进度详情
function collapseAllProgressDetails(assistantMessageId, progressId) {
// 折叠集成到MCP区域的详情
const detailsId = 'process-details-' + assistantMessageId;
const detailsContainer = document.getElementById(detailsId);
if (detailsContainer) {
const timeline = detailsContainer.querySelector('.progress-timeline');
if (timeline && timeline.classList.contains('expanded')) {
timeline.classList.remove('expanded');
const btn = document.querySelector(`#${assistantMessageId} .process-detail-btn`);
if (btn) {
btn.innerHTML = '<span>展开详情</span>';
if (assistantMessageId) {
const detailsId = 'process-details-' + assistantMessageId;
const detailsContainer = document.getElementById(detailsId);
if (detailsContainer) {
const timeline = detailsContainer.querySelector('.progress-timeline');
if (timeline) {
// 确保移除expanded类无论是否包含
timeline.classList.remove('expanded');
const btn = document.querySelector(`#${assistantMessageId} .process-detail-btn`);
if (btn) {
btn.innerHTML = '<span>展开详情</span>';
}
}
}
}
@@ -497,7 +500,7 @@ function collapseAllProgressDetails(assistantMessageId, progressId) {
allDetails.forEach(detail => {
const timeline = detail.querySelector('.progress-timeline');
const toggleBtn = detail.querySelector('.progress-toggle');
if (timeline && timeline.classList.contains('expanded')) {
if (timeline) {
timeline.classList.remove('expanded');
if (toggleBtn) {
toggleBtn.textContent = '展开详情';
@@ -509,7 +512,7 @@ function collapseAllProgressDetails(assistantMessageId, progressId) {
if (progressId) {
const progressTimeline = document.getElementById(progressId + '-timeline');
const progressToggleBtn = document.querySelector(`#${progressId} .progress-toggle`);
if (progressTimeline && progressTimeline.classList.contains('expanded')) {
if (progressTimeline) {
progressTimeline.classList.remove('expanded');
if (progressToggleBtn) {
progressToggleBtn.textContent = '展开详情';
@@ -592,10 +595,11 @@ function integrateProgressToMCPSection(progressId, assistantMessageId) {
</div>
`;
// 确保初始状态是折叠的(默认折叠)
// 确保初始状态是折叠的(默认折叠,特别是错误时
if (hasContent) {
const timeline = document.getElementById(detailsId + '-timeline');
if (timeline) {
// 如果有错误,确保折叠;否则也默认折叠
timeline.classList.remove('expanded');
}
@@ -844,16 +848,74 @@ function handleStreamEvent(event, progressElement, progressId,
break;
case 'cancelled':
// 显示错误
addTimelineItem(timeline, 'cancelled', {
title: '⛔ 任务已取消',
message: event.message,
data: event.data
});
// 更新进度标题为取消状态
const cancelTitle = document.querySelector(`#${progressId} .progress-title`);
if (cancelTitle) {
cancelTitle.textContent = '⛔ 任务已取消';
}
finalizeProgressTask(progressId, '已取消');
// 更新进度容器为已完成状态添加completed类
const cancelProgressContainer = document.querySelector(`#${progressId} .progress-container`);
if (cancelProgressContainer) {
cancelProgressContainer.classList.add('completed');
}
// 完成进度任务(标记为已取消)
if (progressTaskState.has(progressId)) {
finalizeProgressTask(progressId, '已取消');
}
// 如果取消事件包含messageId说明有助手消息需要显示取消内容
if (event.data && event.data.messageId) {
// 检查助手消息是否已存在
let assistantId = event.data.messageId;
let assistantElement = document.getElementById(assistantId);
// 如果助手消息不存在,创建它
if (!assistantElement) {
assistantId = addMessage('assistant', event.message, null, progressId);
setAssistantId(assistantId);
assistantElement = document.getElementById(assistantId);
} else {
// 如果已存在,更新内容
const bubble = assistantElement.querySelector('.message-bubble');
if (bubble) {
bubble.innerHTML = escapeHtml(event.message).replace(/\n/g, '<br>');
}
}
// 将进度详情集成到工具调用区域(如果还没有)
if (assistantElement) {
const detailsId = 'process-details-' + assistantId;
if (!document.getElementById(detailsId)) {
integrateProgressToMCPSection(progressId, assistantId);
}
// 立即折叠详情(取消时应该默认折叠)
setTimeout(() => {
collapseAllProgressDetails(assistantId, progressId);
}, 100);
}
} else {
// 如果没有messageId创建助手消息并集成详情
const assistantId = addMessage('assistant', event.message, null, progressId);
setAssistantId(assistantId);
// 将进度详情集成到工具调用区域
setTimeout(() => {
integrateProgressToMCPSection(progressId, assistantId);
// 确保详情默认折叠
collapseAllProgressDetails(assistantId, progressId);
}, 100);
}
// 立即刷新任务状态
loadActiveTasks();
break;
@@ -895,6 +957,23 @@ function handleStreamEvent(event, progressElement, progressId,
data: event.data
});
// 更新进度标题为错误状态
const errorTitle = document.querySelector(`#${progressId} .progress-title`);
if (errorTitle) {
errorTitle.textContent = '❌ 执行失败';
}
// 更新进度容器为已完成状态添加completed类
const progressContainer = document.querySelector(`#${progressId} .progress-container`);
if (progressContainer) {
progressContainer.classList.add('completed');
}
// 完成进度任务(标记为失败)
if (progressTaskState.has(progressId)) {
finalizeProgressTask(progressId, '已失败');
}
// 如果错误事件包含messageId说明有助手消息需要显示错误内容
if (event.data && event.data.messageId) {
// 检查助手消息是否已存在
@@ -925,6 +1004,17 @@ function handleStreamEvent(event, progressElement, progressId,
collapseAllProgressDetails(assistantId, progressId);
}, 100);
}
} else {
// 如果没有messageId比如任务已运行时的错误创建助手消息并集成详情
const assistantId = addMessage('assistant', event.message, null, progressId);
setAssistantId(assistantId);
// 将进度详情集成到工具调用区域
setTimeout(() => {
integrateProgressToMCPSection(progressId, assistantId);
// 确保详情默认折叠
collapseAllProgressDetails(assistantId, progressId);
}, 100);
}
// 立即刷新任务状态(执行失败时任务状态会更新)
@@ -1301,6 +1391,8 @@ function renderProcessDetails(messageId, processDetails) {
itemTitle = `${statusIcon} 工具 ${escapeHtml(toolName)} 执行${success ? '完成' : '失败'}`;
} else if (eventType === 'error') {
itemTitle = '❌ 错误';
} else if (eventType === 'cancelled') {
itemTitle = '⛔ 任务已取消';
}
addTimelineItem(timeline, eventType, {
@@ -1309,6 +1401,20 @@ function renderProcessDetails(messageId, processDetails) {
data: data
});
});
// 检查是否有错误或取消事件,如果有,确保详情默认折叠
const hasErrorOrCancelled = processDetails.some(d =>
d.eventType === 'error' || d.eventType === 'cancelled'
);
if (hasErrorOrCancelled) {
// 确保时间线是折叠的
timeline.classList.remove('expanded');
// 更新按钮文本为"展开详情"
const processDetailBtn = messageElement.querySelector('.process-detail-btn');
if (processDetailBtn) {
processDetailBtn.innerHTML = '<span>展开详情</span>';
}
}
}
// 移除消息
@@ -1608,12 +1714,32 @@ async function loadConversation(conversationId) {
// 加载消息
if (conversation.messages && conversation.messages.length > 0) {
conversation.messages.forEach(msg => {
const messageId = addMessage(msg.role, msg.content, msg.mcpExecutionIds || []);
// 检查消息内容是否为"处理中..."如果是检查processDetails中是否有错误或取消事件
let displayContent = msg.content;
if (msg.role === 'assistant' && msg.content === '处理中...' && msg.processDetails && msg.processDetails.length > 0) {
// 查找最后一个error或cancelled事件
for (let i = msg.processDetails.length - 1; i >= 0; i--) {
const detail = msg.processDetails[i];
if (detail.eventType === 'error' || detail.eventType === 'cancelled') {
displayContent = detail.message || msg.content;
break;
}
}
}
const messageId = addMessage(msg.role, displayContent, msg.mcpExecutionIds || []);
// 如果有过程详情,显示它们
if (msg.processDetails && msg.processDetails.length > 0 && msg.role === 'assistant') {
// 延迟一下,确保消息已经渲染
setTimeout(() => {
renderProcessDetails(messageId, msg.processDetails);
// 检查是否有错误或取消事件,如果有,确保详情默认折叠
const hasErrorOrCancelled = msg.processDetails.some(d =>
d.eventType === 'error' || d.eventType === 'cancelled'
);
if (hasErrorOrCancelled) {
collapseAllProgressDetails(messageId, null);
}
}, 100);
}
});