Fix missing results for parallel Eino tool calls.

Merge streaming tool outputs by CallID with ConcatMessages, pair same-name historical results, and FIFO-match duplicate IDs so concurrent nmap 1/2 and 2/2 stay distinct.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
公明
2026-08-19 00:29:12 +08:00
committed by temp
co-authored by Cursor
parent ac6e04a94c
commit 24d06c5220
13 changed files with 522 additions and 89 deletions
+28 -5
View File
@@ -6255,21 +6255,44 @@ function coalesceProcessDetailsToolPairs(details) {
createdAt: detail.createdAt,
data: Object.assign({}, data)
};
if (id) callsById.set(id, copy);
if (id) {
let list = callsById.get(id);
if (!list) {
list = [];
callsById.set(id, list);
}
list.push(copy);
}
fifoCalls.push(copy);
out.push(copy);
} else if (et === 'tool_result') {
} else if (et === 'tool_result') {
let target = null;
if (id && callsById.has(id)) {
target = callsById.get(id);
} else {
const list = callsById.get(id);
while (list.length) {
const candidate = list.shift();
if (candidate && candidate.data && !candidate.data._mergedResult) {
target = candidate;
break;
}
}
}
if (!target) {
const resultName = String(data.toolName || '').trim().toLowerCase();
let anyUnmatched = null;
for (let j = 0; j < fifoCalls.length; j++) {
const c = fifoCalls[j];
if (c && c.data && !c.data._mergedResult) {
if (!c || !c.data || c.data._mergedResult) continue;
if (!anyUnmatched) anyUnmatched = c;
const callName = String(c.data.toolName || '').trim().toLowerCase();
if (!resultName || !callName || callName === resultName) {
target = c;
break;
}
}
if (!target && id) {
target = anyUnmatched;
}
}
if (target) {
// agentFacing 或较新的 tool_result 覆盖旧合并(历史数据可能含 reduction 前全量正文)
@@ -16,3 +16,10 @@ test('历史 process_details 合并时也会从 tool_result 补齐 tool_call 参
assert.match(source, /targetDetail\.data\.argumentsObj = resultArgs;/);
assert.match(source, /targetDetail\.data\.arguments = JSON\.stringify\(resultArgs\);/);
});
test('同一 toolCallId 的多次调用按 FIFO 合并结果,避免后一次覆盖导致结果记录缺失', () => {
const source = fs.readFileSync('web/static/js/monitor.js', 'utf8');
assert.match(source, /list\.push\(copy\)/);
assert.match(source, /const candidate = list\.shift\(\)/);
assert.match(source, /callName === resultName/);
});