Add files via upload

This commit is contained in:
公明
2026-06-18 12:46:46 +08:00
committed by GitHub
parent 7eadccbff6
commit 6712344411
5 changed files with 62 additions and 87 deletions
+2 -1
View File
@@ -2353,7 +2353,8 @@
"copyContent": "Copy content",
"correctInfo": "Correct info",
"errorInfo": "Error info",
"copyError": "Copy error"
"copyError": "Copy error",
"contentTruncated": "… (display truncated; use read_file on the path in persisted-output for the full file)"
},
"attackChainModal": {
"title": "Attack chain",
+2 -1
View File
@@ -2341,7 +2341,8 @@
"copyContent": "复制内容",
"correctInfo": "正确信息",
"errorInfo": "错误信息",
"copyError": "复制错误"
"copyError": "复制错误",
"contentTruncated": "…(展示已截断;完整内容见 persisted-output 中的文件路径,用 read_file 读取)"
},
"attackChainModal": {
"title": "攻击链可视化",
+56 -25
View File
@@ -2639,6 +2639,57 @@ async function batchUpdateButtonToolNames(buttonsContainer, executionIds) {
}
// 显示MCP调用详情
const MCP_DETAIL_MAX_CHARS = 120000;
function extractMCPResultText(result) {
if (!result) return '';
const content = result.content;
if (typeof content === 'string') return content;
if (Array.isArray(content)) {
return content
.map(item => (item && typeof item === 'object' && typeof item.text === 'string') ? item.text : '')
.filter(Boolean)
.join('\n\n');
}
if (content && typeof content === 'object' && typeof content.text === 'string') {
return content.text;
}
return '';
}
function truncateMCPDetailText(text, maxChars) {
if (text == null) return '';
const s = String(text);
if (s.length <= maxChars) return s;
const hint = typeof window.t === 'function'
? window.t('mcpDetailModal.contentTruncated')
: '…(展示已截断;完整内容见 persisted-output 中的文件路径,用 read_file 读取)';
return s.slice(0, maxChars) + '\n\n' + hint;
}
/** 响应结果区 JSON 展示(过大时截断 content 内 text,避免 stringify 卡死页面) */
function formatMCPResultJsonForDisplay(result, maxChars) {
if (!result) return '{}';
const payload = {
content: result.content,
isError: !!result.isError
};
let json = JSON.stringify(payload, null, 2);
if (json.length <= maxChars) {
return json;
}
const text = extractMCPResultText(result);
const truncatedPayload = {
content: [{ type: 'text', text: truncateMCPDetailText(text, Math.min(maxChars - 800, MCP_DETAIL_MAX_CHARS)) }],
isError: !!result.isError
};
json = JSON.stringify(truncatedPayload, null, 2);
if (json.length > maxChars) {
return json.slice(0, maxChars) + '\n…';
}
return json;
}
async function showMCPDetail(executionId) {
try {
openAppModal('mcp-detail-modal', { focus: false });
@@ -2700,42 +2751,22 @@ async function showMCPDetail(executionId) {
}
if (exec.result) {
const responseData = {
content: exec.result.content,
isError: exec.result.isError
};
responseElement.textContent = JSON.stringify(responseData, null, 2);
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 (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 (successSection && successElement) {
successSection.style.display = 'block';
let successText = '';
const content = exec.result.content;
if (typeof content === 'string') {
successText = content;
} else if (Array.isArray(content)) {
const texts = content
.map(item => (item && typeof item === 'object' && typeof item.text === 'string') ? item.text : '')
.filter(Boolean);
if (texts.length > 0) {
successText = texts.join('\n\n');
}
} else if (content && typeof content === 'object' && typeof content.text === 'string') {
successText = content.text;
}
if (!successText) {
successText = typeof window.t === 'function' ? window.t('mcpDetailModal.execSuccessNoContent') : '执行成功,未返回可展示的文本内容。';
}
successElement.textContent = successText;
successElement.textContent = agentVisibleText || emptyText;
}
}
} else {
+2 -38
View File
@@ -2059,45 +2059,9 @@ function handleStreamEvent(event, progressElement, progressId,
}
break;
case 'tool_result_delta': {
const deltaInfo = event.data || {};
const toolCallId = deltaInfo.toolCallId || null;
if (!toolCallId) break;
const key = toolResultStreamKey(progressId, toolCallId);
let state = toolResultStreamStateByKey.get(key);
const deltaText = event.message || '';
if (!deltaText) break;
if (!state) {
const mapping = getToolCallMapping(progressId, toolCallId);
let callItemId = mapping && mapping.itemId ? mapping.itemId : null;
if (callItemId) {
const callItem = document.getElementById(callItemId);
if (callItem) {
ensureToolCallResultSlot(callItem);
const section = callItem.querySelector('.tool-result-section');
if (section) {
section.classList.remove('pending');
section.className = 'tool-result-section success';
}
}
}
state = { itemId: callItemId, buffer: '', onCallItem: !!callItemId };
toolResultStreamStateByKey.set(key, state);
}
state.buffer += deltaText;
const item = state.itemId ? document.getElementById(state.itemId) : null;
if (item) {
const pre = item.querySelector('pre.tool-result');
if (pre) {
pre.classList.remove('tool-result-pending');
scheduleStreamPlainTextUpdate(pre, state.buffer);
}
}
case 'tool_result_delta':
// 工具执行过程不流式展示,仅等 tool_result 展示最终结果。
break;
}
case 'tool_result':
const resultInfo = event.data || {};
-22
View File
@@ -3391,28 +3391,6 @@ function runWebshellAiSend(conn, inputEl, sendBtn, messagesContainer) {
}
if (!streamingTarget) assistantDiv.textContent = '…';
// ─── Tool result delta (streaming output) ───
} else if (_et === 'tool_result_delta' && _ed.toolCallId) {
var trdKey = _ed.toolCallId;
var trdDelta = _em || '';
if (trdDelta) {
var trdState = wsToolResultStreams.get(trdKey);
if (!trdState) {
var callEl = wsToolCallItems.get(trdKey);
trdState = { el: callEl || null, buf: '', onCall: !!callEl };
wsToolResultStreams.set(trdKey, trdState);
}
trdState.buf += trdDelta;
if (trdState.el) {
var trdPre = trdState.el.querySelector('pre.tool-result');
if (trdPre) {
trdPre.classList.remove('tool-result-pending');
trdPre.textContent = trdState.buf;
}
}
}
if (!streamingTarget) assistantDiv.textContent = '…';
// ─── Tool result (final) ───
} else if (_et === 'tool_result' && _ed) {
var success = _ed.success !== false;