Add files via upload

This commit is contained in:
公明
2026-07-21 15:07:52 +08:00
committed by GitHub
parent 2b63e3b633
commit d7181cb1cd
3 changed files with 361 additions and 175 deletions
+126 -66
View File
@@ -5316,8 +5316,8 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
}
#mcp-detail-modal {
background: rgba(3, 7, 18, 0.66);
backdrop-filter: blur(8px);
background: rgba(3, 7, 18, 0.58);
backdrop-filter: blur(4px);
}
#mcp-detail-modal .mcp-detail-content {
@@ -5325,20 +5325,19 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
max-width: 980px;
max-height: min(86vh, 880px);
margin: 6vh auto;
border-radius: 16px;
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.98));
border: 1px solid rgba(148, 163, 184, 0.26);
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
border-radius: 12px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.28);
box-shadow: 0 18px 48px rgba(15, 23, 42, 0.18);
}
#mcp-detail-modal .modal-header {
min-height: 68px;
padding: 18px 24px;
background: rgba(255, 255, 255, 0.72);
border-bottom: 1px solid rgba(148, 163, 184, 0.22);
min-height: 64px;
padding: 16px 24px;
background: #ffffff;
border-bottom: 1px solid rgba(148, 163, 184, 0.18);
box-shadow: none;
backdrop-filter: blur(14px);
backdrop-filter: none;
}
#mcp-detail-modal .modal-header h2 {
@@ -5355,34 +5354,32 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
#mcp-detail-modal .modal-header h2::before {
content: '';
width: 6px;
height: 26px;
width: 4px;
height: 22px;
border-radius: 999px;
background: linear-gradient(180deg, #6366f1 0%, #38bdf8 100%);
box-shadow: 0 0 18px rgba(99, 102, 241, 0.38);
background: #64748b;
box-shadow: none;
flex: 0 0 auto;
}
#mcp-detail-modal .modal-body {
padding: 24px 26px 26px;
background: linear-gradient(180deg, rgba(248, 250, 252, 0.62), rgba(241, 245, 249, 0.36));
background: #f8fafc;
}
#mcp-detail-modal .detail-section {
margin-bottom: 18px;
padding: 20px 22px;
border-radius: 12px;
background: rgba(255, 255, 255, 0.8);
border: 1px solid rgba(148, 163, 184, 0.22);
box-shadow: 0 12px 34px rgba(15, 23, 42, 0.05);
border-radius: 10px;
background: #ffffff;
border: 1px solid rgba(148, 163, 184, 0.18);
box-shadow: none;
}
#mcp-detail-modal .detail-section-overview {
padding: 14px 16px;
background:
radial-gradient(circle at top left, rgba(59, 130, 246, 0.13), transparent 42%),
linear-gradient(145deg, rgba(255, 255, 255, 0.92), rgba(239, 246, 255, 0.68));
border-color: rgba(59, 130, 246, 0.22);
background: #f8fafc;
border-color: rgba(148, 163, 184, 0.22);
}
#mcp-detail-modal .detail-section-header {
@@ -5399,8 +5396,29 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
}
#mcp-detail-modal .detail-section-header .btn-ghost {
border-color: rgba(37, 99, 235, 0.16);
background: rgba(37, 99, 235, 0.06);
border-color: rgba(148, 163, 184, 0.24);
background: rgba(248, 250, 252, 0.72);
color: var(--text-secondary);
min-height: 32px;
padding: 5px 12px;
border-radius: 8px;
font-size: 0.8rem;
line-height: 1.2;
box-shadow: none;
}
#mcp-detail-modal .detail-section-header .btn-ghost:hover {
border-color: rgba(100, 116, 139, 0.34);
background: #ffffff;
color: var(--text-primary);
}
#mcp-detail-modal .detail-section-header .btn-ghost:disabled {
cursor: default;
opacity: 1;
border-color: rgba(34, 197, 94, 0.24);
background: rgba(240, 253, 244, 0.72);
color: #15803d;
}
#mcp-detail-modal .detail-info-grid {
@@ -5412,9 +5430,9 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
min-width: 0;
min-height: 58px;
padding: 10px 12px;
border-radius: 9px;
background: rgba(15, 23, 42, 0.035);
border-color: rgba(148, 163, 184, 0.2);
border-radius: 8px;
background: #ffffff;
border-color: rgba(148, 163, 184, 0.18);
box-shadow: none;
}
@@ -5443,18 +5461,18 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
#mcp-detail-modal .status-chip {
width: fit-content;
min-width: 88px;
padding: 5px 12px;
min-width: 76px;
padding: 4px 10px;
font-size: 0.82rem;
}
#mcp-detail-modal .detail-code-card {
padding: 0;
overflow: hidden;
background: #0b1120;
border: 1px solid rgba(148, 163, 184, 0.18);
border-radius: 12px;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
background: #f8fafc;
border: 1px solid rgba(148, 163, 184, 0.2);
border-radius: 8px;
box-shadow: none;
}
#mcp-detail-modal .detail-result-tabs {
@@ -5462,17 +5480,17 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
align-items: center;
gap: 4px;
margin: -2px 0 12px;
padding: 4px;
border: 1px solid rgba(148, 163, 184, 0.22);
border-radius: 10px;
background: rgba(15, 23, 42, 0.045);
padding: 3px;
border: 1px solid rgba(148, 163, 184, 0.2);
border-radius: 8px;
background: #f8fafc;
}
#mcp-detail-modal .detail-result-tab {
min-height: 30px;
padding: 0 12px;
border: 0;
border-radius: 7px;
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
font-size: 0.82rem;
@@ -5484,7 +5502,7 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
#mcp-detail-modal .detail-result-tab.active {
background: #ffffff;
color: var(--text-primary);
box-shadow: 0 5px 14px rgba(15, 23, 42, 0.08);
box-shadow: none;
}
#mcp-detail-modal .detail-result-tab.disabled,
@@ -5508,7 +5526,7 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
border: 0;
border-radius: 0;
background: transparent;
color: #dbeafe;
color: #0f172a;
font-size: 0.84rem;
line-height: 1.7;
white-space: pre-wrap;
@@ -5517,7 +5535,22 @@ html[data-theme="dark"] .login-card .login-submit:disabled {
}
#mcp-detail-modal .code-block.error {
color: #fecaca;
color: #991b1b;
}
#mcp-detail-modal .code-block::-webkit-scrollbar {
width: 10px;
height: 10px;
}
#mcp-detail-modal .code-block::-webkit-scrollbar-thumb {
background: rgba(100, 116, 139, 0.36);
border: 2px solid rgba(248, 250, 252, 0.9);
border-radius: 999px;
}
#mcp-detail-modal .code-block::-webkit-scrollbar-track {
background: rgba(226, 232, 240, 0.62);
}
#mcp-detail-modal .detail-success-wrapper {
@@ -34189,18 +34222,18 @@ html[data-theme="dark"] #skill-view-body {
}
html[data-theme="dark"] #mcp-detail-modal {
background: rgba(2, 6, 23, 0.72);
background: rgba(2, 6, 23, 0.62);
}
html[data-theme="dark"] #mcp-detail-modal .mcp-detail-content {
background: linear-gradient(180deg, #111827 0%, #0f172a 100%) !important;
border-color: rgba(96, 165, 250, 0.16);
box-shadow: 0 28px 80px rgba(0, 0, 0, 0.46);
background: #111827 !important;
border-color: rgba(148, 163, 184, 0.16);
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.34);
}
html[data-theme="dark"] #mcp-detail-modal .modal-header {
background: rgba(15, 23, 42, 0.78) !important;
border-bottom-color: rgba(148, 163, 184, 0.16) !important;
background: #111827 !important;
border-bottom-color: rgba(148, 163, 184, 0.14) !important;
}
html[data-theme="dark"] #mcp-detail-modal .modal-header h2 {
@@ -34210,26 +34243,22 @@ html[data-theme="dark"] #mcp-detail-modal .modal-header h2 {
}
html[data-theme="dark"] #mcp-detail-modal .modal-body {
background:
radial-gradient(circle at top right, rgba(37, 99, 235, 0.12), transparent 42%),
linear-gradient(180deg, rgba(15, 23, 42, 0.95), rgba(2, 6, 23, 0.88));
background: #0f172a;
}
html[data-theme="dark"] #mcp-detail-modal .detail-section {
background: rgba(15, 23, 42, 0.72);
background: #111827;
border-color: rgba(148, 163, 184, 0.14);
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.16);
box-shadow: none;
}
html[data-theme="dark"] #mcp-detail-modal .detail-section-overview {
background:
radial-gradient(circle at top left, rgba(59, 130, 246, 0.2), transparent 44%),
linear-gradient(145deg, rgba(15, 23, 42, 0.92), rgba(17, 24, 39, 0.74));
border-color: rgba(59, 130, 246, 0.24);
background: #111827;
border-color: rgba(148, 163, 184, 0.16);
}
html[data-theme="dark"] #mcp-detail-modal .detail-info-grid .detail-item {
background: rgba(2, 6, 23, 0.42);
background: #0f172a;
border-color: rgba(148, 163, 184, 0.14);
}
@@ -34237,14 +34266,32 @@ html[data-theme="dark"] #mcp-detail-modal .detail-item strong {
color: #94a3b8;
}
html[data-theme="dark"] #mcp-detail-modal .detail-section-header .btn-ghost {
background: #0f172a;
border-color: rgba(148, 163, 184, 0.18);
color: #94a3b8;
}
html[data-theme="dark"] #mcp-detail-modal .detail-section-header .btn-ghost:hover {
background: #1f2937;
border-color: rgba(148, 163, 184, 0.26);
color: #e5e7eb;
}
html[data-theme="dark"] #mcp-detail-modal .detail-section-header .btn-ghost:disabled {
background: rgba(20, 83, 45, 0.22);
border-color: rgba(74, 222, 128, 0.18);
color: #86efac;
}
html[data-theme="dark"] #mcp-detail-modal .detail-code-card {
background: #020617;
border-color: rgba(148, 163, 184, 0.16);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035);
border-color: rgba(148, 163, 184, 0.14);
box-shadow: none;
}
html[data-theme="dark"] #mcp-detail-modal .detail-result-tabs {
background: rgba(2, 6, 23, 0.38);
background: #0f172a;
border-color: rgba(148, 163, 184, 0.14);
}
@@ -34253,9 +34300,9 @@ html[data-theme="dark"] #mcp-detail-modal .detail-result-tab {
}
html[data-theme="dark"] #mcp-detail-modal .detail-result-tab.active {
background: rgba(59, 130, 246, 0.16);
color: #dbeafe;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.16);
background: #1f2937;
color: #e5e7eb;
box-shadow: none;
}
html[data-theme="dark"] #mcp-detail-modal .detail-code-card .code-block,
@@ -34265,6 +34312,19 @@ html[data-theme="dark"] #mcp-detail-modal .code-block {
color: #dbeafe;
}
html[data-theme="dark"] #mcp-detail-modal .code-block.error {
color: #fecaca;
}
html[data-theme="dark"] #mcp-detail-modal .code-block::-webkit-scrollbar-thumb {
background: rgba(148, 163, 184, 0.42);
border-color: rgba(2, 6, 23, 0.95);
}
html[data-theme="dark"] #mcp-detail-modal .code-block::-webkit-scrollbar-track {
background: rgba(15, 23, 42, 0.72);
}
html[data-theme="dark"] #mcp-detail-modal .detail-success-wrapper {
background: rgba(20, 83, 45, 0.16);
border-color: rgba(34, 197, 94, 0.28);
+209 -96
View File
@@ -2466,6 +2466,19 @@ function isProcessDetailsUserExpanded(messageId) {
return !!(container && container.dataset && container.dataset.userExpanded === '1');
}
function messageHasConversationContent(messageElement) {
if (!messageElement || !messageElement.classList || !messageElement.classList.contains('assistant')) return false;
if (messageElement.hasAttribute('data-system-ready-message')) return false;
if (messageElement.dataset && String(messageElement.dataset.backendMessageId || '').trim()) return true;
const raw = messageElement.dataset ? String(messageElement.dataset.originalContent || '').trim() : '';
if (raw) return true;
const bubble = messageElement.querySelector('.message-bubble');
if (!bubble) return false;
const clone = bubble.cloneNode(true);
clone.querySelectorAll('.message-copy-btn').forEach((btn) => btn.remove());
return String(clone.textContent || '').trim().length > 0;
}
function syncProcessDetailButtonLabels(messageId, expanded) {
const expandT = typeof window.t === 'function' ? window.t('chat.expandDetail') : '展开详情';
const collapseT = typeof window.t === 'function' ? window.t('tasks.collapseDetail') : '收起详情';
@@ -2522,7 +2535,8 @@ function renderProcessDetails(messageId, processDetails, options) {
const isLazyRequest = (processDetails === null);
const reasoningFromMessage = getMessageReasoningContent(messageElement);
const backendId = messageElement.dataset ? String(messageElement.dataset.backendMessageId || '').trim() : '';
if (isLazyRequest && !reasoningFromMessage && !backendId && getMcpExecutionCount(messageElement) <= 0) {
const hasConversationContent = !!renderOpts.force || messageHasConversationContent(messageElement);
if (isLazyRequest && !reasoningFromMessage && !backendId && getMcpExecutionCount(messageElement) <= 0 && !hasConversationContent) {
pruneEmptyMcpCallSection(messageElement);
return;
}
@@ -3084,11 +3098,12 @@ function pruneEmptyMcpCallSection(messageElement) {
const chrome = getExistingMcpCallSectionChrome(messageElement);
if (!chrome || !chrome.mcpSection) return;
const hasDetails = !!chrome.mcpSection.querySelector('.process-details-container');
const hasProcessDetailButton = !!(chrome.toolbar && chrome.toolbar.querySelector('.process-detail-btn'));
const hasToolButtons = !!(chrome.toolList && chrome.toolList.querySelector('.mcp-detail-btn'));
const hasPendingTools = getPendingMcpExecutionCount(messageElement) > 0 ||
getPendingToolExecutionSummaryCount(messageElement) > 0 ||
getMcpExecutionCount(messageElement) > 0;
if (!hasDetails && !hasToolButtons && !hasPendingTools) {
if (!hasDetails && !hasProcessDetailButton && !hasToolButtons && !hasPendingTools) {
chrome.mcpSection.remove();
}
}
@@ -3419,6 +3434,34 @@ async function focusToolExecutionInProcessDetails(messageElement, summary, index
}, 2200);
}
async function findToolExecutionTimelineItem(messageElement, summary, index) {
const item = normalizeToolExecutionSummaryForButton(summary);
let detailsContainer = await ensureProcessDetailsForToolFocus(messageElement, item.processDetailId || '');
let timeline = detailsContainer && detailsContainer.querySelector('.progress-timeline');
if (!timeline) return null;
let target = null;
if (item.processDetailId) {
target = timeline.querySelector('[data-process-detail-id="' + cssEscapeValue(item.processDetailId) + '"]');
}
if (!target && item.toolCallId) {
target = timeline.querySelector('[data-tool-call-id="' + cssEscapeValue(item.toolCallId) + '"]');
}
if (!target) {
const toolItems = timeline.querySelectorAll('.timeline-item-tool_call');
target = toolItems[index] || null;
}
if (!target && item.processDetailId && messageElement.dataset && messageElement.dataset.backendMessageId && typeof window.loadProcessDetailsPaginated === 'function') {
await window.loadProcessDetailsPaginated(messageElement.id, messageElement.dataset.backendMessageId, {
autoLoadAll: false,
anchorId: item.processDetailId
});
detailsContainer = document.getElementById('process-details-' + messageElement.id);
timeline = detailsContainer && detailsContainer.querySelector('.progress-timeline');
target = timeline ? timeline.querySelector('[data-process-detail-id="' + cssEscapeValue(item.processDetailId) + '"]') : null;
}
return target;
}
async function resolveToolExecutionSummaryForFocus(messageElement, executionId, index) {
const wantedExecutionId = executionId == null ? '' : String(executionId).trim();
let summaries = getCachedToolExecutionSummaries(messageElement);
@@ -3482,6 +3525,77 @@ window.setMcpExecutionSummaryCount = setMcpExecutionSummaryCount;
window.setPendingMcpExecutionIds = setPendingMcpExecutionIds;
window.setPendingToolExecutionSummaries = setPendingToolExecutionSummaries;
async function fetchProcessDetailDataForModal(detailId) {
const id = detailId != null ? String(detailId).trim() : '';
if (!id || typeof apiFetch !== 'function') return null;
const res = await apiFetch('/api/process-details/' + encodeURIComponent(id));
const j = await res.json().catch(() => ({}));
if (!res.ok) return null;
const detail = j && j.processDetail ? j.processDetail : null;
return detail && detail.data ? detail.data : null;
}
function processToolResultToMCPResult(resultData, rawText) {
if (!resultData) return null;
const isError = !!(resultData.isError || resultData.success === false);
let text = rawText;
if (text == null || String(text) === '') {
const noResultText = typeof window.t === 'function' ? window.t('timeline.noResult') : '无结果';
const result = resultData.result != null ? resultData.result : (resultData.error != null ? resultData.error : noResultText);
text = typeof result === 'string' ? result : JSON.stringify(result);
}
return {
content: [{ type: 'text', text: String(text || '') }],
isError: isError
};
}
async function showMCPDetailFromProcessToolItem(messageElement, summary, index) {
const target = await findToolExecutionTimelineItem(messageElement, summary, index);
if (!target) {
alert(typeof window.t === 'function'
? window.t('chat.toolExecutionDetailPending')
: '工具执行详情尚未同步,请稍后重试。');
return;
}
const state = typeof window.getToolCallDetailState === 'function'
? window.getToolCallDetailState(target)
: {};
let args = state.args;
let resultData = state.resultData;
let rawText = state.rawText;
if ((!args || Object.keys(args).length === 0) && state.processDetailId) {
const fullCall = await fetchProcessDetailDataForModal(state.processDetailId);
if (fullCall) {
args = typeof window.parseToolCallArgsFromData === 'function'
? window.parseToolCallArgsFromData(fullCall)
: (fullCall.argumentsObj || {});
}
}
const resultDetailId = state.resultDetailId || target.dataset.toolResultDetailId || '';
if (!resultData && resultDetailId) {
resultData = await fetchProcessDetailDataForModal(resultDetailId);
}
const toolName = (summary && summary.toolName) || target.dataset.toolName || (typeof window.t === 'function' ? window.t('chat.unknownTool') : '未知工具');
const success = resultData ? !(resultData.isError || resultData.success === false) : target.dataset.toolSuccess !== '0';
const status = resultData || target.classList.contains('tool-call-completed') || target.classList.contains('tool-call-failed')
? (success ? 'completed' : 'failed')
: 'running';
const exec = {
id: (resultData && resultData.executionId) || (summary && summary.executionId) || '',
toolName: toolName,
status: status,
startTime: target.dataset.createdAtIso || '',
arguments: args || {},
result: processToolResultToMCPResult(resultData, rawText),
error: resultData && resultData.error ? String(resultData.error) : ''
};
openAppModal('mcp-detail-modal', { focus: false });
deferModalContent(function () {
renderMCPDetailModal(exec);
});
}
async function openTaskToolExecutionDetail(messageElement, item, index) {
let detailItem = item;
if (!detailItem.executionId) {
@@ -3496,9 +3610,7 @@ async function openTaskToolExecutionDetail(messageElement, item, index) {
await showMCPDetail(detailItem.executionId);
return;
}
alert(typeof window.t === 'function'
? window.t('chat.toolExecutionDetailPending')
: '工具执行详情尚未同步,请稍后重试。');
await showMCPDetailFromProcessToolItem(messageElement, detailItem, index);
}
/**
@@ -3779,6 +3891,97 @@ function copyActiveMCPResultDetail(triggerBtn = null) {
copyDetailBlock(activeBlock ? activeBlock.id : 'detail-response', triggerBtn);
}
function renderMCPDetailModal(exec) {
exec = exec || {};
document.getElementById('detail-tool-name').textContent = exec.toolName || (typeof window.t === 'function' ? window.t('mcpDetailModal.unknown') : 'Unknown');
document.getElementById('detail-execution-id').textContent = exec.id || 'N/A';
const statusEl = document.getElementById('detail-status');
const normalizedStatus = (exec.status || 'unknown').toLowerCase();
statusEl.textContent = getStatusText(exec.status);
statusEl.className = `status-chip status-${normalizedStatus}`;
try {
statusEl.dataset.detailStatus = (exec.status || '') + '';
} catch (e) { /* ignore */ }
const detailTimeLocale = (typeof window.__locale === 'string' && window.__locale.startsWith('zh')) ? 'zh-CN' : 'en-US';
const detailTimeEl = document.getElementById('detail-time');
if (detailTimeEl) {
detailTimeEl.textContent = exec.startTime
? new Date(exec.startTime).toLocaleString(detailTimeLocale)
: '—';
try {
detailTimeEl.dataset.detailTimeIso = exec.startTime ? new Date(exec.startTime).toISOString() : '';
} catch (e) { /* ignore */ }
}
const requestData = {
tool: exec.toolName,
arguments: exec.arguments
};
document.getElementById('detail-request').textContent = JSON.stringify(requestData, null, 2);
const responseElement = document.getElementById('detail-response');
const successElement = document.getElementById('detail-success');
const errorSection = document.getElementById('detail-error-section');
const errorElement = document.getElementById('detail-error');
responseElement.className = 'code-block';
responseElement.textContent = '';
if (successElement) {
successElement.className = 'code-block';
successElement.textContent = '';
}
if (errorSection && errorElement) {
errorSection.style.display = 'none';
errorElement.textContent = '';
}
setMCPResultDetailTabs('raw', false);
if (exec.result) {
const agentVisibleText = truncateMCPDetailText(extractMCPResultText(exec.result), MCP_DETAIL_MAX_CHARS);
const emptyText = typeof window.t === 'function' ? window.t('mcpDetailModal.execSuccessNoContent') : '执行成功,未返回可展示的文本内容。';
if (exec.result.isError) {
responseElement.className = 'code-block error';
responseElement.textContent = formatMCPResultJsonForDisplay(exec.result, MCP_DETAIL_MAX_CHARS);
if (successElement) {
successElement.textContent = '';
}
setMCPResultDetailTabs('raw', false);
if (exec.error && errorSection && errorElement) {
errorSection.style.display = 'block';
errorElement.textContent = exec.error;
}
} else {
responseElement.className = 'code-block';
responseElement.textContent = formatMCPResultJsonForDisplay(exec.result, MCP_DETAIL_MAX_CHARS);
if (successElement) {
successElement.textContent = agentVisibleText || emptyText;
}
setMCPResultDetailTabs('success', true);
}
} else {
if (normalizedStatus === 'running') {
responseElement.textContent = typeof window.t === 'function' ? window.t('mcpDetailModal.runningNoResponseYet') : '尚无返回,工具可能仍在执行。若长时间无响应,可在下方终止本次调用。';
} else {
responseElement.textContent = typeof window.t === 'function' ? window.t('chat.noResponseData') : '暂无响应数据';
}
setMCPResultDetailTabs('raw', false);
}
const abortSection = document.getElementById('detail-abort-section');
const abortBtn = document.getElementById('detail-abort-btn');
if (abortSection && abortBtn) {
if (normalizedStatus === 'running' && exec.id) {
abortSection.style.display = 'block';
abortBtn.dataset.execId = exec.id || '';
abortBtn.textContent = typeof window.t === 'function' ? window.t('mcpDetailModal.abortBtn') : '终止工具';
} else {
abortSection.style.display = 'none';
delete abortBtn.dataset.execId;
}
}
}
async function showMCPDetail(executionId) {
try {
openAppModal('mcp-detail-modal', { focus: false });
@@ -3792,97 +3995,7 @@ async function showMCPDetail(executionId) {
}
deferModalContent(function () {
// 填充模态框内容
document.getElementById('detail-tool-name').textContent = exec.toolName || (typeof window.t === 'function' ? window.t('mcpDetailModal.unknown') : 'Unknown');
document.getElementById('detail-execution-id').textContent = exec.id || 'N/A';
const statusEl = document.getElementById('detail-status');
const normalizedStatus = (exec.status || 'unknown').toLowerCase();
statusEl.textContent = getStatusText(exec.status);
statusEl.className = `status-chip status-${normalizedStatus}`;
try {
statusEl.dataset.detailStatus = (exec.status || '') + '';
} catch (e) { /* ignore */ }
const detailTimeLocale = (typeof window.__locale === 'string' && window.__locale.startsWith('zh')) ? 'zh-CN' : 'en-US';
const detailTimeEl = document.getElementById('detail-time');
if (detailTimeEl) {
detailTimeEl.textContent = exec.startTime
? new Date(exec.startTime).toLocaleString(detailTimeLocale)
: '—';
try {
detailTimeEl.dataset.detailTimeIso = exec.startTime ? new Date(exec.startTime).toISOString() : '';
} catch (e) { /* ignore */ }
}
// 请求参数
const requestData = {
tool: exec.toolName,
arguments: exec.arguments
};
document.getElementById('detail-request').textContent = JSON.stringify(requestData, null, 2);
// 响应结果 + 正确信息 / 错误信息
const responseElement = document.getElementById('detail-response');
const successElement = document.getElementById('detail-success');
const errorSection = document.getElementById('detail-error-section');
const errorElement = document.getElementById('detail-error');
// 重置状态
responseElement.className = 'code-block';
responseElement.textContent = '';
if (successElement) {
successElement.className = 'code-block';
successElement.textContent = '';
}
if (errorSection && errorElement) {
errorSection.style.display = 'none';
errorElement.textContent = '';
}
setMCPResultDetailTabs('raw', false);
if (exec.result) {
const agentVisibleText = truncateMCPDetailText(extractMCPResultText(exec.result), MCP_DETAIL_MAX_CHARS);
const emptyText = typeof window.t === 'function' ? window.t('mcpDetailModal.execSuccessNoContent') : '执行成功,未返回可展示的文本内容。';
if (exec.result.isError) {
responseElement.className = 'code-block error';
responseElement.textContent = formatMCPResultJsonForDisplay(exec.result, MCP_DETAIL_MAX_CHARS);
if (successElement) {
successElement.textContent = '';
}
setMCPResultDetailTabs('raw', false);
if (exec.error && errorSection && errorElement) {
errorSection.style.display = 'block';
errorElement.textContent = exec.error;
}
} else {
responseElement.className = 'code-block';
responseElement.textContent = formatMCPResultJsonForDisplay(exec.result, MCP_DETAIL_MAX_CHARS);
if (successElement) {
successElement.textContent = agentVisibleText || emptyText;
}
setMCPResultDetailTabs('success', true);
}
} else {
if (normalizedStatus === 'running') {
responseElement.textContent = typeof window.t === 'function' ? window.t('mcpDetailModal.runningNoResponseYet') : '尚无返回,工具可能仍在执行。若长时间无响应,可在下方终止本次调用。';
} else {
responseElement.textContent = typeof window.t === 'function' ? window.t('chat.noResponseData') : '暂无响应数据';
}
setMCPResultDetailTabs('raw', false);
}
const abortSection = document.getElementById('detail-abort-section');
const abortBtn = document.getElementById('detail-abort-btn');
if (abortSection && abortBtn) {
if (normalizedStatus === 'running') {
abortSection.style.display = 'block';
abortBtn.dataset.execId = exec.id || '';
abortBtn.textContent = typeof window.t === 'function' ? window.t('mcpDetailModal.abortBtn') : '终止工具';
} else {
abortSection.style.display = 'none';
delete abortBtn.dataset.execId;
}
}
renderMCPDetailModal(exec);
});
} catch (error) {
closeMCPDetail();
+26 -13
View File
@@ -1281,7 +1281,6 @@ function getAssistantId() {
// 将进度详情集成到工具调用区域(流式阶段助手消息不挂 mcp 条,结束时在此创建,避免图二整行 MCP 芯片样式)
function integrateProgressToMCPSection(progressId, assistantMessageId, mcpExecutionIds) {
const progressElement = document.getElementById(progressId);
if (!progressElement) return;
// 只 flush 终态标题/正文;完成后的详情回看统一走后端分页,不再复制实时 DOM 快照。
flushAllPendingStreamPlainUpdates();
@@ -2001,7 +2000,8 @@ function handleStreamEvent(event, progressElement, progressId,
}
const timeline = resolveStreamTimeline(progressId);
if (!timeline) return;
const canHandleWithoutTimeline = ['conversation', 'response', 'error', 'cancelled', 'done'].includes(String(event.type || ''));
if (!timeline && !canHandleWithoutTimeline) return;
// 终态事件(error/cancelled)优先复用现有助手消息,避免重复追加相同报错
const upsertTerminalAssistantMessage = (message, preferredMessageId = null) => {
@@ -2735,11 +2735,13 @@ function handleStreamEvent(event, progressElement, progressId,
case 'cancelled':
const taskCancelledText = typeof window.t === 'function' ? window.t('chat.taskCancelled') : '任务已取消';
addTimelineItem(timeline, 'cancelled', {
title: '⛔ ' + taskCancelledText,
message: event.message,
data: event.data
});
if (timeline) {
addTimelineItem(timeline, 'cancelled', {
title: '⛔ ' + taskCancelledText,
message: event.message,
data: event.data
});
}
const cancelTitle = document.querySelector(`#${progressId} .progress-title`);
if (cancelTitle) {
cancelTitle.textContent = '⛔ ' + taskCancelledText;
@@ -2922,7 +2924,7 @@ function handleStreamEvent(event, progressElement, progressId,
// 将 response_start/response_delta 占位固化为 planning,与后端落库一致后再快照过程详情
if (streamState && streamState.itemId) {
finalizeMainResponseStreamItem(streamState, event.message, responseData);
} else if (bubbleText && String(bubbleText).trim() && !isEinoEmptyResponsePlaceholder(event.message)) {
} else if (timeline && bubbleText && String(bubbleText).trim() && !isEinoEmptyResponsePlaceholder(event.message)) {
addTimelineItem(timeline, 'planning', {
title: typeof einoMainStreamPlanningTitle === 'function'
? einoMainStreamPlanningTitle(responseData)
@@ -2972,11 +2974,13 @@ function handleStreamEvent(event, progressElement, progressId,
case 'error':
// 显示错误
addTimelineItem(timeline, 'error', {
title: '❌ ' + (typeof window.t === 'function' ? window.t('chat.error') : '错误'),
message: event.message,
data: event.data
});
if (timeline) {
addTimelineItem(timeline, 'error', {
title: '❌ ' + (typeof window.t === 'function' ? window.t('chat.error') : '错误'),
message: event.message,
data: event.data
});
}
// 更新进度标题为错误状态
const errorTitle = document.querySelector(`#${progressId} .progress-title`);
@@ -3799,6 +3803,11 @@ function buildToolResultSectionHtml(data, opts) {
const toolCallDetailStateByItemId = new Map();
function getToolCallDetailState(item) {
if (!item || !item.id) return {};
return Object.assign({}, toolCallDetailStateByItemId.get(item.id) || {});
}
function setToolCallDetailState(item, state) {
if (!item || !item.id) return;
toolCallDetailStateByItemId.set(item.id, Object.assign({}, state || {}));
@@ -3807,6 +3816,8 @@ function setToolCallDetailState(item, state) {
updateToolDetailToggleLabel(item);
}
window.getToolCallDetailState = getToolCallDetailState;
function toolDetailToggleText(expanded) {
if (typeof window.t === 'function') {
return expanded
@@ -6577,7 +6588,9 @@ function reconcileMonitorExecutionRows(tbody, rowEntries) {
const nextRow = createMonitorExecutionRow(entry);
if (!nextRow) return;
if (row && row.parentNode === tbody) {
const replacingCursor = row === cursor;
row.replaceWith(nextRow);
if (replacingCursor) cursor = nextRow;
}
row = nextRow;
existingById.set(entry.id, row);