Add files via upload

This commit is contained in:
公明
2026-03-29 01:19:35 +08:00
committed by GitHub
parent 9e03f06cda
commit 628604fcae
5 changed files with 87 additions and 6 deletions
+18
View File
@@ -2871,6 +2871,24 @@ header {
background: rgba(0, 102, 255, 0.05);
}
/* Eino 多代理:主编排器 vs 子代理时间线区分 */
.timeline-eino-role-orchestrator {
border-left-color: #5c6bc0 !important;
background: rgba(92, 107, 192, 0.09) !important;
}
.timeline-eino-role-sub {
border-left-color: #00897b !important;
background: rgba(0, 137, 123, 0.08) !important;
}
.timeline-item-iteration.timeline-eino-scope-main {
border-left-color: #3949ab !important;
background: rgba(57, 73, 171, 0.1) !important;
}
.timeline-item-iteration.timeline-eino-scope-sub {
border-left-color: #00695c !important;
background: rgba(0, 105, 92, 0.09) !important;
}
.timeline-item-thinking {
border-left-color: #9c27b0;
background: rgba(156, 39, 176, 0.05);
+3
View File
@@ -147,6 +147,8 @@
"addNewGroup": "+ New group",
"callNumber": "Call #{{n}}",
"iterationRound": "Iteration {{n}}",
"einoOrchestratorRound": "Orchestrator · round {{n}}",
"einoSubAgentStep": "Sub-agent {{agent}} · step {{n}}",
"aiThinking": "AI thinking",
"planning": "Planning",
"toolCallsDetected": "Detected {{count}} tool call(s)",
@@ -156,6 +158,7 @@
"knowledgeRetrieval": "Knowledge retrieval",
"knowledgeRetrievalTag": "Knowledge retrieval",
"error": "Error",
"streamNetworkErrorHint": "Connection lost ({{detail}}). A long task may still be running on the server; check running tasks at the top or refresh this conversation later.",
"taskCancelled": "Task cancelled",
"unknownTool": "Unknown tool",
"einoAgentReplyTitle": "Sub-agent reply",
+3
View File
@@ -147,6 +147,8 @@
"addNewGroup": "+ 新增分组",
"callNumber": "调用 #{{n}}",
"iterationRound": "第 {{n}} 轮迭代",
"einoOrchestratorRound": "主代理 · 第 {{n}} 轮",
"einoSubAgentStep": "子代理 {{agent}} · 第 {{n}} 步",
"aiThinking": "AI思考",
"planning": "规划中",
"toolCallsDetected": "检测到 {{count}} 个工具调用",
@@ -156,6 +158,7 @@
"knowledgeRetrieval": "知识检索",
"knowledgeRetrievalTag": "知识检索",
"error": "错误",
"streamNetworkErrorHint": "连接已中断({{detail}})。长时间任务可能仍在后端执行,请查看顶部「运行中」任务或稍后刷新本对话。",
"taskCancelled": "任务已取消",
"unknownTool": "未知工具",
"einoAgentReplyTitle": "子代理回复",
+12 -1
View File
@@ -361,7 +361,18 @@ async function sendMessage() {
} catch (error) {
removeMessage(progressId);
addMessage('system', '错误: ' + error.message);
const msg = error && error.message != null ? String(error.message) : String(error);
const isNetwork = /network|fetch|Failed to fetch|aborted|AbortError|load failed|NetworkError/i.test(msg);
if (isNetwork && typeof window.t === 'function') {
addMessage('system', window.t('chat.streamNetworkErrorHint', { detail: msg }));
} else if (isNetwork) {
addMessage('system', '连接已中断(' + msg + ')。长时间任务可能仍在后端执行,请查看顶部运行中任务或稍后刷新对话。');
} else {
addMessage('system', '错误: ' + msg);
}
if (typeof loadActiveTasks === 'function') {
loadActiveTasks();
}
// 发送失败时,不恢复草稿,因为消息已经显示在对话框中了
}
}
+51 -5
View File
@@ -96,6 +96,21 @@ function timelineAgentBracketPrefix(data) {
return s ? ('[' + s + '] ') : '';
}
/** 主/子代理视觉区分:左边框与浅底色(与工具黄/绿状态并存时由具体项类型覆盖次要边) */
function applyEinoTimelineRole(item, data) {
if (!item || !data) return;
const role = data.einoRole;
if (role === 'orchestrator' || role === 'sub') {
item.dataset.einoRole = role;
item.classList.add('timeline-eino-role-' + role);
}
const scope = data.einoScope;
if (scope === 'main' || scope === 'sub') {
item.dataset.einoScope = scope;
item.classList.add('timeline-eino-scope-' + scope);
}
}
// markdown 渲染(用于最终合并渲染;流式增量阶段用纯转义避免部分语法不稳定)
const assistantMarkdownSanitizeConfig = {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 's', 'code', 'pre', 'blockquote', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'a', 'img', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'hr'],
@@ -710,15 +725,32 @@ function handleStreamEvent(event, progressElement, progressId,
}, 200);
}
break;
case 'iteration':
// 添加迭代标记(data 属性供语言切换时重算标题)
case 'iteration': {
const d = event.data || {};
const n = d.iteration != null ? d.iteration : 1;
let iterTitle;
if (d.einoScope === 'main') {
iterTitle = typeof window.t === 'function'
? window.t('chat.einoOrchestratorRound', { n: n })
: ('主代理 · 第 ' + n + ' 轮');
} else if (d.einoScope === 'sub') {
const ag = d.einoAgent != null ? String(d.einoAgent).trim() : '';
iterTitle = typeof window.t === 'function'
? window.t('chat.einoSubAgentStep', { n: n, agent: ag })
: ('子代理 · ' + ag + ' · 第 ' + n + ' 步');
} else {
iterTitle = typeof window.t === 'function'
? window.t('chat.iterationRound', { n: n })
: ('第 ' + n + ' 轮迭代');
}
addTimelineItem(timeline, 'iteration', {
title: typeof window.t === 'function' ? window.t('chat.iterationRound', { n: event.data?.iteration || 1 }) : '第 ' + (event.data?.iteration || 1) + ' 轮迭代',
title: iterTitle,
message: event.message,
data: event.data,
iterationN: event.data?.iteration || 1
iterationN: n
});
break;
}
case 'thinking_stream_start': {
const d = event.data || {};
@@ -1381,6 +1413,9 @@ function addTimelineItem(timeline, type, options) {
if (type === 'iteration') {
const n = options.iterationN != null ? options.iterationN : (options.data && options.data.iteration != null ? options.data.iteration : 1);
item.dataset.iterationN = String(n);
if (options.data && options.data.einoScope) {
item.dataset.einoScope = String(options.data.einoScope);
}
}
if (type === 'progress' && options.message) {
item.dataset.progressMessage = options.message;
@@ -1493,6 +1528,9 @@ function addTimelineItem(timeline, type, options) {
}
item.innerHTML = content;
if (options.data) {
applyEinoTimelineRole(item, options.data);
}
timeline.appendChild(item);
// 自动展开详情
@@ -2298,7 +2336,15 @@ function refreshProgressAndTimelineI18n() {
const ap = (item.dataset.einoAgent && item.dataset.einoAgent !== '') ? ('[' + item.dataset.einoAgent + '] ') : '';
if (type === 'iteration' && item.dataset.iterationN) {
const n = parseInt(item.dataset.iterationN, 10) || 1;
titleSpan.textContent = ap + _t('chat.iterationRound', { n: n });
const scope = item.dataset.einoScope;
if (scope === 'main') {
titleSpan.textContent = _t('chat.einoOrchestratorRound', { n: n });
} else if (scope === 'sub') {
const agent = item.dataset.einoAgent || '';
titleSpan.textContent = _t('chat.einoSubAgentStep', { n: n, agent: agent });
} else {
titleSpan.textContent = ap + _t('chat.iterationRound', { n: n });
}
} else if (type === 'thinking') {
titleSpan.textContent = ap + '\uD83E\uDD14 ' + _t('chat.aiThinking');
} else if (type === 'tool_calls_detected' && item.dataset.toolCallsCount != null) {