myagent-ai 1.32.9 → 1.32.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/web/ui/chat/chat_main.js +2 -0
- package/web/ui/chat/flow_engine.js +122 -4
package/package.json
CHANGED
package/web/ui/chat/chat_main.js
CHANGED
|
@@ -3526,6 +3526,8 @@ function groupHistoryMessages(messages) {
|
|
|
3526
3526
|
// ── [v1.23.20] 统一消息渲染函数:历史消息和流式消息共享 ──
|
|
3527
3527
|
// 生成单条消息的完整 HTML(message-row 外壳 + 所有内部内容)
|
|
3528
3528
|
// 流式结束后也用此函数重建 DOM,确保历史/流式样式完全一致
|
|
3529
|
+
// [v1.32.9] 流式结束后 _normalizeMessageAfterStreaming() 将 parts 转为 groupHistoryMessages() 格式,
|
|
3530
|
+
// 所以无论数据来源如何,此函数都走同一渲染分支
|
|
3529
3531
|
window.buildMessageHtml = function(msg, idx, agent) {
|
|
3530
3532
|
const isUser = msg.role === 'user';
|
|
3531
3533
|
if (msg.role === 'tool') return '';
|
|
@@ -1373,11 +1373,13 @@ function showToolResultModal(msgIndex, eventId) {
|
|
|
1373
1373
|
if (msg.exec_events) {
|
|
1374
1374
|
evt = msg.exec_events.find(e => String(e.id) === String(eventId));
|
|
1375
1375
|
}
|
|
1376
|
-
// 再从 parts 查找(V2
|
|
1376
|
+
// 再从 parts 查找(V2 格式或规范化后的 exec 格式)
|
|
1377
1377
|
if (!evt && msg.parts) {
|
|
1378
1378
|
for (const part of msg.parts) {
|
|
1379
|
-
|
|
1380
|
-
|
|
1379
|
+
// [v1.32.9] 同时支持 v2_tool 和规范化后的 exec 格式
|
|
1380
|
+
const inner = (part.type === 'v2_tool') ? part.data : (part.type === 'exec') ? part.data : null;
|
|
1381
|
+
if (inner && String(inner.id) === String(eventId)) {
|
|
1382
|
+
evt = inner;
|
|
1381
1383
|
break;
|
|
1382
1384
|
}
|
|
1383
1385
|
}
|
|
@@ -1532,6 +1534,112 @@ function _assembleV2Content(msg, msgParts) {
|
|
|
1532
1534
|
return '(无回复)';
|
|
1533
1535
|
}
|
|
1534
1536
|
|
|
1537
|
+
// ══════════════════════════════════════════════════════
|
|
1538
|
+
// ── [v1.32.9] Post-Streaming Normalization ──
|
|
1539
|
+
// ══════════════════════════════════════════════════════
|
|
1540
|
+
|
|
1541
|
+
/**
|
|
1542
|
+
* 流式结束后,将 msg.parts 规范化为与 groupHistoryMessages() 一致的格式。
|
|
1543
|
+
* 这确保 buildMessageHtml() 在流式和历史两条路径上走同一个渲染分支,
|
|
1544
|
+
* 避免视觉差异。
|
|
1545
|
+
*
|
|
1546
|
+
* 主要处理:
|
|
1547
|
+
* 1. v2_tool (tool_start + tool_result) → exec (合并卡片,与历史格式对齐)
|
|
1548
|
+
* 2. 仅含1个文本部分且无工具调用时 → 删除 parts(走简单气泡路径,与历史对齐)
|
|
1549
|
+
* 3. v2_ask → 保留原样
|
|
1550
|
+
*/
|
|
1551
|
+
function _normalizeMessageAfterStreaming(msg) {
|
|
1552
|
+
if (!msg || !Array.isArray(msg.parts) || msg.parts.length === 0) return;
|
|
1553
|
+
|
|
1554
|
+
// ── Step 1: 转换 v2_tool 为 exec 格式,并合并 tool_start + tool_result ──
|
|
1555
|
+
var normalizedParts = [];
|
|
1556
|
+
var evtIdCounter = 0;
|
|
1557
|
+
|
|
1558
|
+
for (var i = 0; i < msg.parts.length; i++) {
|
|
1559
|
+
var part = msg.parts[i];
|
|
1560
|
+
|
|
1561
|
+
if (part.type === 'v2_tool') {
|
|
1562
|
+
var inner = part.data || {};
|
|
1563
|
+
// tool_start: 创建 exec 卡片
|
|
1564
|
+
if (inner.type === 'tool_start' || inner.status === 'running') {
|
|
1565
|
+
var execPart = {
|
|
1566
|
+
type: 'exec',
|
|
1567
|
+
data: {
|
|
1568
|
+
id: evtIdCounter,
|
|
1569
|
+
type: 'tool_call',
|
|
1570
|
+
title: inner.title || inner.tool_name || '工具调用',
|
|
1571
|
+
tool_name: inner.tool_name || '',
|
|
1572
|
+
params: inner.params,
|
|
1573
|
+
status: 'done',
|
|
1574
|
+
has_result: false,
|
|
1575
|
+
result_data: null,
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
// 向后搜索同一 tool_name 的 tool_result 进行合并
|
|
1579
|
+
for (var ri = i + 1; ri < msg.parts.length; ri++) {
|
|
1580
|
+
var rp = msg.parts[ri];
|
|
1581
|
+
if (rp.type === 'v2_tool' && rp.data && rp.data.type === 'tool_result') {
|
|
1582
|
+
var rInner = rp.data;
|
|
1583
|
+
if (rInner.tool_name === inner.tool_name || rInner.id === inner.id) {
|
|
1584
|
+
execPart.data.has_result = true;
|
|
1585
|
+
execPart.data.success = rInner.success;
|
|
1586
|
+
execPart.data.summary = rInner.summary ? rInner.summary.substring(0, 500).trim() : undefined;
|
|
1587
|
+
execPart.data.result = rInner.result || { output: rInner.summary || '' };
|
|
1588
|
+
if (rInner.title) execPart.data.title = rInner.title;
|
|
1589
|
+
// 标记已消费
|
|
1590
|
+
rp._consumed = true;
|
|
1591
|
+
break;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
// 遇到下一个 tool_start 就停止搜索
|
|
1595
|
+
if (rp.type === 'v2_tool' && rp.data && (rp.data.type === 'tool_start' || rp.data.status === 'running')) break;
|
|
1596
|
+
}
|
|
1597
|
+
evtIdCounter++;
|
|
1598
|
+
normalizedParts.push(execPart);
|
|
1599
|
+
} else if (inner.type === 'tool_result' && !part._consumed) {
|
|
1600
|
+
// 孤立的 tool_result(没有匹配的 tool_start)
|
|
1601
|
+
evtIdCounter++;
|
|
1602
|
+
normalizedParts.push({
|
|
1603
|
+
type: 'exec',
|
|
1604
|
+
data: {
|
|
1605
|
+
id: evtIdCounter,
|
|
1606
|
+
type: 'tool_result',
|
|
1607
|
+
title: inner.title || inner.tool_name || '工具结果',
|
|
1608
|
+
tool_name: inner.tool_name || '',
|
|
1609
|
+
success: inner.success,
|
|
1610
|
+
summary: inner.summary ? inner.summary.substring(0, 500).trim() : undefined,
|
|
1611
|
+
result: inner.result || { output: inner.summary || '' },
|
|
1612
|
+
has_result: true,
|
|
1613
|
+
}
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
// 其他 v2_tool 类型(如已完成但非 start/result 的),也转为 exec
|
|
1617
|
+
else if (inner.type !== 'tool_start' && inner.type !== 'tool_result') {
|
|
1618
|
+
evtIdCounter++;
|
|
1619
|
+
normalizedParts.push({
|
|
1620
|
+
type: 'exec',
|
|
1621
|
+
data: Object.assign({}, inner, { id: evtIdCounter })
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
} else {
|
|
1625
|
+
// text / exec / v2_ask 等类型保持不变
|
|
1626
|
+
normalizedParts.push(part);
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
// ── Step 2: 与 groupHistoryMessages() 对齐——决定是否保留 parts ──
|
|
1631
|
+
// groupHistoryMessages 逻辑: 仅当 hasExecParts || textParts.length > 1 时设置 parts
|
|
1632
|
+
var textParts = normalizedParts.filter(function(p) { return p.type === 'text'; });
|
|
1633
|
+
var hasExecParts = normalizedParts.some(function(p) { return p.type === 'exec'; });
|
|
1634
|
+
|
|
1635
|
+
if (hasExecParts || textParts.length > 1) {
|
|
1636
|
+
msg.parts = normalizedParts;
|
|
1637
|
+
} else {
|
|
1638
|
+
// 仅1段文本且无工具调用 → 删除 parts,走简单气泡渲染路径
|
|
1639
|
+
delete msg.parts;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1535
1643
|
// ══════════════════════════════════════════════════════
|
|
1536
1644
|
// ── Voice Input: User Bubble Replacement ──
|
|
1537
1645
|
// ══════════════════════════════════════════════════════
|
|
@@ -1899,6 +2007,8 @@ async function sendMessage(opts) {
|
|
|
1899
2007
|
state.messages[msgIdx].content = _assembleV2Content(state.messages[msgIdx], msgParts);
|
|
1900
2008
|
state.messages[msgIdx]._streamingText = '';
|
|
1901
2009
|
if (allExecEvents.length > 0) state.messages[msgIdx].exec_events = [...allExecEvents];
|
|
2010
|
+
// [v1.32.9] 规范化 parts 为 groupHistoryMessages() 格式
|
|
2011
|
+
_normalizeMessageAfterStreaming(state.messages[msgIdx]);
|
|
1902
2012
|
}
|
|
1903
2013
|
// Start new message
|
|
1904
2014
|
state.messages.push({ role: 'user', content: evt.message, time: new Date().toISOString() });
|
|
@@ -2308,6 +2418,8 @@ async function sendMessage(opts) {
|
|
|
2308
2418
|
state.messages[msgIdx].exec_events = allExecEvents;
|
|
2309
2419
|
// Assemble final content: prefer V2 reasoning/ask text over raw XML
|
|
2310
2420
|
state.messages[msgIdx].content = _assembleV2Content(state.messages[msgIdx], msgParts);
|
|
2421
|
+
// [v1.32.9] 规范化 parts 为 groupHistoryMessages() 格式,确保 buildMessageHtml() 渲染一致
|
|
2422
|
+
_normalizeMessageAfterStreaming(state.messages[msgIdx]);
|
|
2311
2423
|
}
|
|
2312
2424
|
|
|
2313
2425
|
// ── 流式传输完成,清除恢复数据 ──
|
|
@@ -2416,7 +2528,13 @@ async function sendMessage(opts) {
|
|
|
2416
2528
|
state.isGenerating = false;
|
|
2417
2529
|
state.abortController = null;
|
|
2418
2530
|
// 重置所有消息的流式标志
|
|
2419
|
-
state.messages.forEach(m => {
|
|
2531
|
+
state.messages.forEach(m => {
|
|
2532
|
+
if(m.streaming) {
|
|
2533
|
+
m.streaming = false;
|
|
2534
|
+
// [v1.32.9] 规范化 parts,确保异常结束时也和历史格式一致
|
|
2535
|
+
_normalizeMessageAfterStreaming(m);
|
|
2536
|
+
}
|
|
2537
|
+
});
|
|
2420
2538
|
hideTypingIndicator();
|
|
2421
2539
|
stopExecTimerPolling();
|
|
2422
2540
|
document.getElementById('sendBtn').style.display = '';
|