mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-07 04:58:03 +02:00
Add files via upload
This commit is contained in:
@@ -2152,13 +2152,17 @@ function appendChatProjectPanelItem(list, project, selectedId, onSelect, tFn) {
|
||||
const t = tFn || tp;
|
||||
const isNone = !project.id;
|
||||
const isSelected = isNone ? !selectedId : selectedId === project.id;
|
||||
const fullDesc = isNone
|
||||
? (project.description || '')
|
||||
: (project.description || '').trim() || t('projects.sharedFactBoard');
|
||||
const desc = isNone
|
||||
? (project.description || '')
|
||||
: (project.description || '').trim().slice(0, 80) || t('projects.sharedFactBoard');
|
||||
: fullDesc.slice(0, 80);
|
||||
const btn = document.createElement('button');
|
||||
btn.type = 'button';
|
||||
btn.className = 'role-selection-item-main' + (isSelected ? ' selected' : '');
|
||||
btn.setAttribute('role', 'option');
|
||||
btn.setAttribute('data-selection-detail', fullDesc);
|
||||
btn.onclick = () => onSelect(project.id || '');
|
||||
btn.innerHTML = `
|
||||
<div class="role-selection-item-icon-main">${isNone ? '—' : '📁'}</div>
|
||||
|
||||
@@ -24,6 +24,79 @@ function rolePlainDescription(role) {
|
||||
if (raw === 'roles.noDescription' || raw === 'roles.noDescriptionShort') return '';
|
||||
return raw;
|
||||
}
|
||||
|
||||
function initSelectionDetailTooltip() {
|
||||
if (window.__selectionDetailTooltipReady) return;
|
||||
window.__selectionDetailTooltipReady = true;
|
||||
|
||||
const tooltip = document.createElement('div');
|
||||
tooltip.className = 'selection-detail-tooltip';
|
||||
tooltip.setAttribute('role', 'tooltip');
|
||||
document.body.appendChild(tooltip);
|
||||
|
||||
let activeEl = null;
|
||||
|
||||
function hideTooltip() {
|
||||
activeEl = null;
|
||||
tooltip.classList.remove('visible', 'placement-left');
|
||||
}
|
||||
|
||||
function positionTooltip(el) {
|
||||
const text = el && el.getAttribute('data-selection-detail');
|
||||
if (!text) {
|
||||
hideTooltip();
|
||||
return;
|
||||
}
|
||||
activeEl = el;
|
||||
tooltip.textContent = text;
|
||||
tooltip.classList.add('visible');
|
||||
|
||||
const rect = el.getBoundingClientRect();
|
||||
const tipRect = tooltip.getBoundingClientRect();
|
||||
const gap = 12;
|
||||
const margin = 12;
|
||||
const rightSpace = window.innerWidth - rect.right - gap - margin;
|
||||
const placeLeft = rightSpace < tipRect.width && rect.left > tipRect.width + gap + margin;
|
||||
const left = placeLeft ? rect.left - tipRect.width - gap : rect.right + gap;
|
||||
const top = Math.max(margin, Math.min(rect.top + rect.height / 2 - tipRect.height / 2, window.innerHeight - tipRect.height - margin));
|
||||
|
||||
tooltip.classList.toggle('placement-left', placeLeft);
|
||||
tooltip.style.left = left + 'px';
|
||||
tooltip.style.top = top + 'px';
|
||||
}
|
||||
|
||||
document.addEventListener('mouseover', function (event) {
|
||||
const el = event.target && event.target.closest && event.target.closest('[data-selection-detail]');
|
||||
if (!el || (event.relatedTarget && el.contains(event.relatedTarget))) return;
|
||||
positionTooltip(el);
|
||||
});
|
||||
document.addEventListener('mouseout', function (event) {
|
||||
const el = event.target && event.target.closest && event.target.closest('[data-selection-detail]');
|
||||
if (!el || (event.relatedTarget && el.contains(event.relatedTarget))) return;
|
||||
hideTooltip();
|
||||
});
|
||||
document.addEventListener('focusin', function (event) {
|
||||
const el = event.target && event.target.closest && event.target.closest('[data-selection-detail]');
|
||||
if (el) positionTooltip(el);
|
||||
});
|
||||
document.addEventListener('focusout', function (event) {
|
||||
const el = event.target && event.target.closest && event.target.closest('[data-selection-detail]');
|
||||
if (el) hideTooltip();
|
||||
});
|
||||
window.addEventListener('scroll', hideTooltip, true);
|
||||
window.addEventListener('resize', function () {
|
||||
if (activeEl) positionTooltip(activeEl);
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initSelectionDetailTooltip);
|
||||
} else {
|
||||
initSelectionDetailTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
let currentRole = localStorage.getItem('currentRole') || '';
|
||||
let roles = [];
|
||||
let rolesSearchKeyword = ''; // 角色搜索关键词
|
||||
@@ -209,10 +282,18 @@ function renderRoleSelectionSidebar() {
|
||||
const isSelected = isDefaultRole ? (currentRole === '' || currentRole === '默认') : (currentRole === role.name);
|
||||
const roleItem = document.createElement('div');
|
||||
roleItem.className = 'role-selection-item-main' + (isSelected ? ' selected' : '');
|
||||
roleItem.setAttribute('role', 'option');
|
||||
roleItem.tabIndex = 0;
|
||||
roleItem.onclick = () => {
|
||||
selectRole(role.name);
|
||||
closeRoleSelectionPanel(); // 选择后自动关闭面板
|
||||
};
|
||||
roleItem.onkeydown = (event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
roleItem.click();
|
||||
}
|
||||
};
|
||||
const icon = getRoleIcon(role);
|
||||
|
||||
// 处理默认角色的描述
|
||||
@@ -221,6 +302,7 @@ function renderRoleSelectionSidebar() {
|
||||
if (isDefaultRole && !plainDesc) {
|
||||
description = _t('roles.defaultRoleDescription');
|
||||
}
|
||||
roleItem.setAttribute('data-selection-detail', description);
|
||||
|
||||
roleItem.innerHTML = `
|
||||
<div class="role-selection-item-icon-main">${icon}</div>
|
||||
|
||||
+16
-10
@@ -223,12 +223,13 @@ function wsRenderRoleList() {
|
||||
var html = '';
|
||||
// 默认角色
|
||||
var defSelected = !cur ? ' selected' : '';
|
||||
html += '<button type="button" class="role-selection-item-main' + defSelected + '" onclick="wsSelectRole(\'\')">' +
|
||||
var defDesc = wsTOr('roles.defaultRoleDescription', '默认角色,不额外携带用户提示词,使用所有工具');
|
||||
html += '<button type="button" class="role-selection-item-main' + defSelected + '" data-selection-detail="' + escapeHtmlAttr(defDesc) + '" onclick="wsSelectRole(\'\')">' +
|
||||
'<div class="role-selection-item-icon-main">\ud83d\udd35</div>' +
|
||||
'<div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' +
|
||||
(wsTOr('chat.defaultRole', '默认')) +
|
||||
'</div><div class="role-selection-item-description-main">' +
|
||||
(wsTOr('roles.defaultRoleDescription', '默认角色,不额外携带用户提示词,使用所有工具')) +
|
||||
escapeHtml(defDesc) +
|
||||
'</div></div>' +
|
||||
(defSelected ? '<div class="role-selection-checkmark-main">\u2713</div>' : '') +
|
||||
'</button>';
|
||||
@@ -238,10 +239,11 @@ function wsRenderRoleList() {
|
||||
if (!r.enabled) continue;
|
||||
if (r.name === '默认') continue; // 已在上方硬编码默认角色,跳过 API 返回的默认项
|
||||
var sel = (r.name === cur) ? ' selected' : '';
|
||||
html += '<button type="button" class="role-selection-item-main' + sel + '" onclick="wsSelectRole(\'' + r.name.replace(/'/g, "\\'") + '\')">' +
|
||||
'<div class="role-selection-item-icon-main">' + (r.icon || '\ud83d\udd35') + '</div>' +
|
||||
'<div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + r.name + '</div>' +
|
||||
'<div class="role-selection-item-description-main">' + (r.description || '').substring(0, 60) + '</div></div>' +
|
||||
var desc = r.description || '';
|
||||
html += '<button type="button" class="role-selection-item-main' + sel + '" data-selection-detail="' + escapeHtmlAttr(desc) + '" onclick="wsSelectRole(\'' + r.name.replace(/'/g, "\\'") + '\')">' +
|
||||
'<div class="role-selection-item-icon-main">' + escapeHtml(r.icon || '\ud83d\udd35') + '</div>' +
|
||||
'<div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + escapeHtml(r.name) + '</div>' +
|
||||
'<div class="role-selection-item-description-main">' + escapeHtml(desc.substring(0, 60)) + '</div></div>' +
|
||||
(sel ? '<div class="role-selection-checkmark-main">\u2713</div>' : '') +
|
||||
'</button>';
|
||||
}
|
||||
@@ -1136,6 +1138,10 @@ function escapeHtml(s) {
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function escapeHtmlAttr(s) {
|
||||
return escapeHtml(s).replace(/"/g, '"').replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function escapeSingleQuotedShellArg(value) {
|
||||
var s = value == null ? '' : String(value);
|
||||
return "'" + s.replace(/'/g, "'\\''") + "'";
|
||||
@@ -2260,10 +2266,10 @@ function selectWebshell(id, stateReady) {
|
||||
'<button type="button" class="role-selection-panel-close" onclick="wsCloseAgentModePanel()"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18 6L6 18M6 6l12 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>' +
|
||||
'</div>' +
|
||||
'<div class="agent-mode-options">' +
|
||||
'<button type="button" class="role-selection-item-main agent-mode-option ws-agent-mode-option" data-value="eino_single" role="option" onclick="wsSelectAgentMode(\'eino_single\')"><div class="role-selection-item-icon-main">\u26a1</div><div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + (wsT('chat.agentModeEinoSingle') || 'Eino 单代理(ADK)') + '</div><div class="role-selection-item-description-main">' + (wsT('chat.agentModeEinoSingleHint') || 'Eino ChatModelAgent + Runner') + '</div></div><div class="role-selection-checkmark-main agent-mode-check" data-agent-mode-check="eino_single">\u2713</div></button>' +
|
||||
'<button type="button" class="role-selection-item-main agent-mode-option ws-agent-mode-option" data-value="deep" role="option" onclick="wsSelectAgentMode(\'deep\')"><div class="role-selection-item-icon-main">\ud83e\udde9</div><div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + (wsT('chat.agentModeDeep') || 'Deep(DeepAgent)') + '</div><div class="role-selection-item-description-main">' + (wsT('chat.agentModeDeepHint') || 'Eino DeepAgent,适合复杂安全测试、多阶段 task 子代理委派与汇总') + '</div></div><div class="role-selection-checkmark-main agent-mode-check" data-agent-mode-check="deep">\u2713</div></button>' +
|
||||
'<button type="button" class="role-selection-item-main agent-mode-option ws-agent-mode-option" data-value="plan_execute" role="option" onclick="wsSelectAgentMode(\'plan_execute\')"><div class="role-selection-item-icon-main">\ud83d\udccb</div><div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + (wsT('chat.agentModePlanExecuteLabel') || 'Plan-Execute') + '</div><div class="role-selection-item-description-main">' + (wsT('chat.agentModePlanExecuteHint') || '规划 → 执行 → 重规划') + '</div></div><div class="role-selection-checkmark-main agent-mode-check" data-agent-mode-check="plan_execute">\u2713</div></button>' +
|
||||
'<button type="button" class="role-selection-item-main agent-mode-option ws-agent-mode-option" data-value="supervisor" role="option" onclick="wsSelectAgentMode(\'supervisor\')"><div class="role-selection-item-icon-main">\ud83c\udfaf</div><div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + (wsT('chat.agentModeSupervisorLabel') || 'Supervisor(专家路由)') + '</div><div class="role-selection-item-description-main">' + (wsT('chat.agentModeSupervisorHint') || '专家路由场景:监督者通过 transfer 动态分派多个专业子代理') + '</div></div><div class="role-selection-checkmark-main agent-mode-check" data-agent-mode-check="supervisor">\u2713</div></button>' +
|
||||
'<button type="button" class="role-selection-item-main agent-mode-option ws-agent-mode-option" data-value="eino_single" role="option" onclick="wsSelectAgentMode(\'eino_single\')" data-agent-mode-detail="' + escapeHtmlAttr(wsT('chat.agentModeEinoSingleHint') || 'Eino ChatModelAgent + Runner') + '"><div class="role-selection-item-icon-main">\u26a1</div><div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + (wsT('chat.agentModeEinoSingle') || 'Eino 单代理(ADK)') + '</div><div class="role-selection-item-description-main">' + (wsT('chat.agentModeEinoSingleHint') || 'Eino ChatModelAgent + Runner') + '</div></div><div class="role-selection-checkmark-main agent-mode-check" data-agent-mode-check="eino_single">\u2713</div></button>' +
|
||||
'<button type="button" class="role-selection-item-main agent-mode-option ws-agent-mode-option" data-value="deep" role="option" onclick="wsSelectAgentMode(\'deep\')" data-agent-mode-detail="' + escapeHtmlAttr(wsT('chat.agentModeDeepHint') || 'Eino DeepAgent,适合复杂安全测试、多阶段 task 子代理委派与汇总') + '"><div class="role-selection-item-icon-main">\ud83e\udde9</div><div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + (wsT('chat.agentModeDeep') || 'Deep(DeepAgent)') + '</div><div class="role-selection-item-description-main">' + (wsT('chat.agentModeDeepHint') || 'Eino DeepAgent,适合复杂安全测试、多阶段 task 子代理委派与汇总') + '</div></div><div class="role-selection-checkmark-main agent-mode-check" data-agent-mode-check="deep">\u2713</div></button>' +
|
||||
'<button type="button" class="role-selection-item-main agent-mode-option ws-agent-mode-option" data-value="plan_execute" role="option" onclick="wsSelectAgentMode(\'plan_execute\')" data-agent-mode-detail="' + escapeHtmlAttr(wsT('chat.agentModePlanExecuteHint') || '规划 → 执行 → 重规划') + '"><div class="role-selection-item-icon-main">\ud83d\udccb</div><div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + (wsT('chat.agentModePlanExecuteLabel') || 'Plan-Execute') + '</div><div class="role-selection-item-description-main">' + (wsT('chat.agentModePlanExecuteHint') || '规划 → 执行 → 重规划') + '</div></div><div class="role-selection-checkmark-main agent-mode-check" data-agent-mode-check="plan_execute">\u2713</div></button>' +
|
||||
'<button type="button" class="role-selection-item-main agent-mode-option ws-agent-mode-option" data-value="supervisor" role="option" onclick="wsSelectAgentMode(\'supervisor\')" data-agent-mode-detail="' + escapeHtmlAttr(wsT('chat.agentModeSupervisorHint') || '专家路由场景:监督者通过 transfer 动态分派多个专业子代理') + '"><div class="role-selection-item-icon-main">\ud83c\udfaf</div><div class="role-selection-item-content-main"><div class="role-selection-item-name-main">' + (wsT('chat.agentModeSupervisorLabel') || 'Supervisor(专家路由)') + '</div><div class="role-selection-item-description-main">' + (wsT('chat.agentModeSupervisorHint') || '专家路由场景:监督者通过 transfer 动态分派多个专业子代理') + '</div></div><div class="role-selection-checkmark-main agent-mode-check" data-agent-mode-check="supervisor">\u2713</div></button>' +
|
||||
'</div></div></div>' +
|
||||
'<input type="hidden" id="ws-agent-mode-select" value="eino_single" autocomplete="off" />' +
|
||||
'</div>' +
|
||||
|
||||
Reference in New Issue
Block a user