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
+30 -2
View File
@@ -290,15 +290,43 @@ func (h *AgentHandler) AgentLoopStream(c *gin.Context) {
defer cancelWithCause(nil) defer cancelWithCause(nil)
if _, err := h.tasks.StartTask(conversationID, req.Message, cancelWithCause); err != nil { if _, err := h.tasks.StartTask(conversationID, req.Message, cancelWithCause); err != nil {
var errorMsg string
if errors.Is(err, ErrTaskAlreadyRunning) { if errors.Is(err, ErrTaskAlreadyRunning) {
sendEvent("error", "当前会话已有任务正在执行,请先停止后再尝试。", map[string]interface{}{ errorMsg = "⚠️ 当前会话已有任务正在执行,请等待当前任务完成或点击「停止任务」按钮后再尝试。"
sendEvent("error", errorMsg, map[string]interface{}{
"conversationId": conversationID, "conversationId": conversationID,
"errorType": "task_already_running",
}) })
} else { } else {
sendEvent("error", "无法启动任务: "+err.Error(), map[string]interface{}{ errorMsg = "无法启动任务: " + err.Error()
sendEvent("error", errorMsg, map[string]interface{}{
"conversationId": conversationID, "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{}{ sendEvent("done", "", map[string]interface{}{
"conversationId": conversationID, "conversationId": conversationID,
}) })
+140 -14
View File
@@ -478,15 +478,18 @@ function toggleProgressDetails(progressId) {
// 折叠所有进度详情 // 折叠所有进度详情
function collapseAllProgressDetails(assistantMessageId, progressId) { function collapseAllProgressDetails(assistantMessageId, progressId) {
// 折叠集成到MCP区域的详情 // 折叠集成到MCP区域的详情
const detailsId = 'process-details-' + assistantMessageId; if (assistantMessageId) {
const detailsContainer = document.getElementById(detailsId); const detailsId = 'process-details-' + assistantMessageId;
if (detailsContainer) { const detailsContainer = document.getElementById(detailsId);
const timeline = detailsContainer.querySelector('.progress-timeline'); if (detailsContainer) {
if (timeline && timeline.classList.contains('expanded')) { const timeline = detailsContainer.querySelector('.progress-timeline');
timeline.classList.remove('expanded'); if (timeline) {
const btn = document.querySelector(`#${assistantMessageId} .process-detail-btn`); // 确保移除expanded类(无论是否包含)
if (btn) { timeline.classList.remove('expanded');
btn.innerHTML = '<span>展开详情</span>'; 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 => { allDetails.forEach(detail => {
const timeline = detail.querySelector('.progress-timeline'); const timeline = detail.querySelector('.progress-timeline');
const toggleBtn = detail.querySelector('.progress-toggle'); const toggleBtn = detail.querySelector('.progress-toggle');
if (timeline && timeline.classList.contains('expanded')) { if (timeline) {
timeline.classList.remove('expanded'); timeline.classList.remove('expanded');
if (toggleBtn) { if (toggleBtn) {
toggleBtn.textContent = '展开详情'; toggleBtn.textContent = '展开详情';
@@ -509,7 +512,7 @@ function collapseAllProgressDetails(assistantMessageId, progressId) {
if (progressId) { if (progressId) {
const progressTimeline = document.getElementById(progressId + '-timeline'); const progressTimeline = document.getElementById(progressId + '-timeline');
const progressToggleBtn = document.querySelector(`#${progressId} .progress-toggle`); const progressToggleBtn = document.querySelector(`#${progressId} .progress-toggle`);
if (progressTimeline && progressTimeline.classList.contains('expanded')) { if (progressTimeline) {
progressTimeline.classList.remove('expanded'); progressTimeline.classList.remove('expanded');
if (progressToggleBtn) { if (progressToggleBtn) {
progressToggleBtn.textContent = '展开详情'; progressToggleBtn.textContent = '展开详情';
@@ -592,10 +595,11 @@ function integrateProgressToMCPSection(progressId, assistantMessageId) {
</div> </div>
`; `;
// 确保初始状态是折叠的(默认折叠) // 确保初始状态是折叠的(默认折叠,特别是错误时
if (hasContent) { if (hasContent) {
const timeline = document.getElementById(detailsId + '-timeline'); const timeline = document.getElementById(detailsId + '-timeline');
if (timeline) { if (timeline) {
// 如果有错误,确保折叠;否则也默认折叠
timeline.classList.remove('expanded'); timeline.classList.remove('expanded');
} }
@@ -844,16 +848,74 @@ function handleStreamEvent(event, progressElement, progressId,
break; break;
case 'cancelled': case 'cancelled':
// 显示错误
addTimelineItem(timeline, 'cancelled', { addTimelineItem(timeline, 'cancelled', {
title: '⛔ 任务已取消', title: '⛔ 任务已取消',
message: event.message, message: event.message,
data: event.data data: event.data
}); });
// 更新进度标题为取消状态
const cancelTitle = document.querySelector(`#${progressId} .progress-title`); const cancelTitle = document.querySelector(`#${progressId} .progress-title`);
if (cancelTitle) { if (cancelTitle) {
cancelTitle.textContent = '⛔ 任务已取消'; 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(); loadActiveTasks();
break; break;
@@ -895,6 +957,23 @@ function handleStreamEvent(event, progressElement, progressId,
data: event.data 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,说明有助手消息,需要显示错误内容 // 如果错误事件包含messageId,说明有助手消息,需要显示错误内容
if (event.data && event.data.messageId) { if (event.data && event.data.messageId) {
// 检查助手消息是否已存在 // 检查助手消息是否已存在
@@ -925,6 +1004,17 @@ function handleStreamEvent(event, progressElement, progressId,
collapseAllProgressDetails(assistantId, progressId); collapseAllProgressDetails(assistantId, progressId);
}, 100); }, 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 ? '完成' : '失败'}`; itemTitle = `${statusIcon} 工具 ${escapeHtml(toolName)} 执行${success ? '完成' : '失败'}`;
} else if (eventType === 'error') { } else if (eventType === 'error') {
itemTitle = '❌ 错误'; itemTitle = '❌ 错误';
} else if (eventType === 'cancelled') {
itemTitle = '⛔ 任务已取消';
} }
addTimelineItem(timeline, eventType, { addTimelineItem(timeline, eventType, {
@@ -1309,6 +1401,20 @@ function renderProcessDetails(messageId, processDetails) {
data: data 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) { if (conversation.messages && conversation.messages.length > 0) {
conversation.messages.forEach(msg => { 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') { if (msg.processDetails && msg.processDetails.length > 0 && msg.role === 'assistant') {
// 延迟一下,确保消息已经渲染 // 延迟一下,确保消息已经渲染
setTimeout(() => { setTimeout(() => {
renderProcessDetails(messageId, msg.processDetails); renderProcessDetails(messageId, msg.processDetails);
// 检查是否有错误或取消事件,如果有,确保详情默认折叠
const hasErrorOrCancelled = msg.processDetails.some(d =>
d.eventType === 'error' || d.eventType === 'cancelled'
);
if (hasErrorOrCancelled) {
collapseAllProgressDetails(messageId, null);
}
}, 100); }, 100);
} }
}); });