From 7823fb6b0c2a04eb81b3b42b72635e4750b9d86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AC=E6=98=8E?= <83812544+Ed1s0nZ@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:03:13 +0800 Subject: [PATCH] Add files via upload --- web/static/js/monitor.js | 18 ++++++++++++++++++ .../js/tool-result-args-backfill.test.cjs | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 web/static/js/tool-result-args-backfill.test.cjs diff --git a/web/static/js/monitor.js b/web/static/js/monitor.js index 2cd2b18b..77926f74 100644 --- a/web/static/js/monitor.js +++ b/web/static/js/monitor.js @@ -5819,6 +5819,13 @@ function parseToolCallArgsFromData(data) { return args; } +function toolCallArgsEmpty(args) { + if (args == null) return true; + if (typeof args !== 'object') return false; + if (Array.isArray(args)) return args.length === 0; + return Object.keys(args).length === 0; +} + function formatToolCallTimelineTitle(toolName, index, total) { const name = toolName || (typeof window.t === 'function' ? window.t('chat.unknownTool') : '未知工具'); const idx = index || 0; @@ -6110,6 +6117,10 @@ function mergeToolResultIntoCallItem(item, data, options) { if (item.classList.contains('tool-call-collapsible')) { const state = toolCallDetailStateByItemId.get(item.id) || {}; + const resultArgs = parseToolCallArgsFromData(data); + if (toolCallArgsEmpty(state.args) && !toolCallArgsEmpty(resultArgs)) { + state.args = resultArgs; + } state.resultData = data; state.rawText = text; state.resultDetailId = data.processDetailId || state.resultDetailId || ''; @@ -6214,6 +6225,13 @@ function coalesceProcessDetailsToolPairs(details) { function absorbResult(targetDetail, resultDetail) { const rd = resultDetail.data || {}; targetDetail.data = targetDetail.data || {}; + if (toolCallArgsEmpty(parseToolCallArgsFromData(targetDetail.data))) { + const resultArgs = parseToolCallArgsFromData(rd); + if (!toolCallArgsEmpty(resultArgs)) { + targetDetail.data.argumentsObj = resultArgs; + targetDetail.data.arguments = JSON.stringify(resultArgs); + } + } targetDetail.data._mergedResult = Object.assign({}, rd); if (resultDetail.id) { targetDetail.data._mergedResultDetailId = resultDetail.id; diff --git a/web/static/js/tool-result-args-backfill.test.cjs b/web/static/js/tool-result-args-backfill.test.cjs new file mode 100644 index 00000000..ba2e6439 --- /dev/null +++ b/web/static/js/tool-result-args-backfill.test.cjs @@ -0,0 +1,18 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); + +test('tool_result 合并回工具调用卡时会回填空参数', () => { + const source = fs.readFileSync('web/static/js/monitor.js', 'utf8'); + assert.match(source, /function toolCallArgsEmpty\(args\)/); + assert.match(source, /const resultArgs = parseToolCallArgsFromData\(data\);/); + assert.match(source, /toolCallArgsEmpty\(state\.args\) && !toolCallArgsEmpty\(resultArgs\)/); + assert.match(source, /state\.args = resultArgs;/); +}); + +test('历史 process_details 合并时也会从 tool_result 补齐 tool_call 参数', () => { + const source = fs.readFileSync('web/static/js/monitor.js', 'utf8'); + assert.match(source, /function absorbResult\(targetDetail, resultDetail\)/); + assert.match(source, /targetDetail\.data\.argumentsObj = resultArgs;/); + assert.match(source, /targetDetail\.data\.arguments = JSON\.stringify\(resultArgs\);/); +});