fix: improve codex tool call live updates
This commit is contained in:
@@ -334,6 +334,26 @@ function createAgentRuntime(deps) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'item.updated': {
|
||||||
|
const item = event.item;
|
||||||
|
if (!item || !item.id || item.type === 'agent_message') break;
|
||||||
|
const tc = ensureCodexToolCall(entry, item);
|
||||||
|
const resultText = codexToolResult(item).slice(0, 2000);
|
||||||
|
tc.done = false;
|
||||||
|
tc.result = resultText;
|
||||||
|
|
||||||
|
wsSend(entry.ws, {
|
||||||
|
type: 'tool_update',
|
||||||
|
toolUseId: item.id,
|
||||||
|
name: tc.name,
|
||||||
|
input: tc.input,
|
||||||
|
result: resultText,
|
||||||
|
kind: tc.kind,
|
||||||
|
meta: tc.meta,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'item.completed': {
|
case 'item.completed': {
|
||||||
const item = event.item;
|
const item = event.item;
|
||||||
if (!item || !item.id) break;
|
if (!item || !item.id) break;
|
||||||
@@ -361,6 +381,7 @@ function createAgentRuntime(deps) {
|
|||||||
const resultText = codexToolResult(item).slice(0, 2000);
|
const resultText = codexToolResult(item).slice(0, 2000);
|
||||||
tc.done = true;
|
tc.done = true;
|
||||||
tc.result = resultText;
|
tc.result = resultText;
|
||||||
|
|
||||||
wsSend(entry.ws, {
|
wsSend(entry.ws, {
|
||||||
type: 'tool_end',
|
type: 'tool_end',
|
||||||
toolUseId: item.id,
|
toolUseId: item.id,
|
||||||
|
|||||||
225
public/app.js
225
public/app.js
@@ -84,6 +84,8 @@
|
|||||||
let pendingText = '';
|
let pendingText = '';
|
||||||
let renderTimer = null;
|
let renderTimer = null;
|
||||||
let activeToolCalls = new Map();
|
let activeToolCalls = new Map();
|
||||||
|
let activeTodoCallTargets = new Map();
|
||||||
|
let toolDomSeq = 0;
|
||||||
let toolGroupCount = 0; // 当前 .msg-tools 直接子节点数(含已有父目录)
|
let toolGroupCount = 0; // 当前 .msg-tools 直接子节点数(含已有父目录)
|
||||||
let hasGrouped = false; // 本次输出是否已触发过折叠
|
let hasGrouped = false; // 本次输出是否已触发过折叠
|
||||||
let cmdMenuIndex = -1;
|
let cmdMenuIndex = -1;
|
||||||
@@ -1365,6 +1367,7 @@
|
|||||||
pendingAttachments = [];
|
pendingAttachments = [];
|
||||||
uploadingAttachments = [];
|
uploadingAttachments = [];
|
||||||
activeToolCalls.clear();
|
activeToolCalls.clear();
|
||||||
|
activeTodoCallTargets.clear();
|
||||||
sendBtn.hidden = false;
|
sendBtn.hidden = false;
|
||||||
abortBtn.hidden = true;
|
abortBtn.hidden = true;
|
||||||
chatTitle.textContent = '新会话';
|
chatTitle.textContent = '新会话';
|
||||||
@@ -1387,6 +1390,7 @@
|
|||||||
abortBtn.hidden = true;
|
abortBtn.hidden = true;
|
||||||
pendingText = '';
|
pendingText = '';
|
||||||
activeToolCalls.clear();
|
activeToolCalls.clear();
|
||||||
|
activeTodoCallTargets.clear();
|
||||||
}
|
}
|
||||||
currentSessionId = snapshot.sessionId;
|
currentSessionId = snapshot.sessionId;
|
||||||
loadedHistorySessionId = snapshot.sessionId;
|
loadedHistorySessionId = snapshot.sessionId;
|
||||||
@@ -1814,6 +1818,27 @@
|
|||||||
appendToolCall(msg.toolUseId, msg.name, msg.input, false, msg.kind || null, msg.meta || null);
|
appendToolCall(msg.toolUseId, msg.name, msg.input, false, msg.kind || null, msg.meta || null);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'tool_update':
|
||||||
|
if (!isGenerating) startGenerating();
|
||||||
|
if (!activeToolCalls.has(msg.toolUseId)) {
|
||||||
|
activeToolCalls.set(msg.toolUseId, {
|
||||||
|
name: msg.name,
|
||||||
|
input: msg.input,
|
||||||
|
kind: msg.kind || null,
|
||||||
|
meta: msg.meta || null,
|
||||||
|
done: false,
|
||||||
|
});
|
||||||
|
appendToolCall(msg.toolUseId, msg.name, msg.input, false, msg.kind || null, msg.meta || null);
|
||||||
|
}
|
||||||
|
activeToolCalls.get(msg.toolUseId).done = false;
|
||||||
|
if (msg.name) activeToolCalls.get(msg.toolUseId).name = msg.name;
|
||||||
|
if (msg.input !== undefined) activeToolCalls.get(msg.toolUseId).input = msg.input;
|
||||||
|
if (msg.kind) activeToolCalls.get(msg.toolUseId).kind = msg.kind;
|
||||||
|
if (msg.meta) activeToolCalls.get(msg.toolUseId).meta = msg.meta;
|
||||||
|
activeToolCalls.get(msg.toolUseId).result = msg.result;
|
||||||
|
updateToolCall(msg.toolUseId, msg.result, false);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'tool_end':
|
case 'tool_end':
|
||||||
if (activeToolCalls.has(msg.toolUseId)) {
|
if (activeToolCalls.has(msg.toolUseId)) {
|
||||||
activeToolCalls.get(msg.toolUseId).done = true;
|
activeToolCalls.get(msg.toolUseId).done = true;
|
||||||
@@ -1821,7 +1846,7 @@
|
|||||||
if (msg.meta) activeToolCalls.get(msg.toolUseId).meta = msg.meta;
|
if (msg.meta) activeToolCalls.get(msg.toolUseId).meta = msg.meta;
|
||||||
activeToolCalls.get(msg.toolUseId).result = msg.result;
|
activeToolCalls.get(msg.toolUseId).result = msg.result;
|
||||||
}
|
}
|
||||||
updateToolCall(msg.toolUseId, msg.result);
|
updateToolCall(msg.toolUseId, msg.result, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'cost':
|
case 'cost':
|
||||||
@@ -1880,6 +1905,7 @@
|
|||||||
toolGroupCount = 0;
|
toolGroupCount = 0;
|
||||||
hasGrouped = false;
|
hasGrouped = false;
|
||||||
activeToolCalls.clear();
|
activeToolCalls.clear();
|
||||||
|
activeTodoCallTargets.clear();
|
||||||
const toolsDiv = document.querySelector('#streaming-msg .msg-tools');
|
const toolsDiv = document.querySelector('#streaming-msg .msg-tools');
|
||||||
if (toolsDiv) toolsDiv.innerHTML = '';
|
if (toolsDiv) toolsDiv.innerHTML = '';
|
||||||
}
|
}
|
||||||
@@ -1896,8 +1922,8 @@
|
|||||||
done: tc.done,
|
done: tc.done,
|
||||||
});
|
});
|
||||||
appendToolCall(tc.id, tc.name, tc.input, tc.done, tc.kind || null, tc.meta || null);
|
appendToolCall(tc.id, tc.name, tc.input, tc.done, tc.kind || null, tc.meta || null);
|
||||||
if (tc.done && tc.result) {
|
if (tc.result !== undefined && tc.result !== null) {
|
||||||
updateToolCall(tc.id, tc.result);
|
updateToolCall(tc.id, tc.result, !!tc.done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2015,6 +2041,7 @@
|
|||||||
pendingText = '';
|
pendingText = '';
|
||||||
window.pendingContentBlocks = [];
|
window.pendingContentBlocks = [];
|
||||||
activeToolCalls.clear();
|
activeToolCalls.clear();
|
||||||
|
activeTodoCallTargets.clear();
|
||||||
toolGroupCount = 0;
|
toolGroupCount = 0;
|
||||||
hasGrouped = false;
|
hasGrouped = false;
|
||||||
sendBtn.hidden = true;
|
sendBtn.hidden = true;
|
||||||
@@ -2062,7 +2089,7 @@
|
|||||||
if (hasGrouped) {
|
if (hasGrouped) {
|
||||||
const toolsDiv = streamEl.querySelector('.msg-tools');
|
const toolsDiv = streamEl.querySelector('.msg-tools');
|
||||||
if (toolsDiv) {
|
if (toolsDiv) {
|
||||||
const loose = Array.from(toolsDiv.children).filter(c => c.classList.contains('tool-call'));
|
const loose = Array.from(toolsDiv.children).filter(isGroupableToolCall);
|
||||||
if (loose.length > 0) {
|
if (loose.length > 0) {
|
||||||
let group = toolsDiv.querySelector(':scope > .tool-group');
|
let group = toolsDiv.querySelector(':scope > .tool-group');
|
||||||
if (!group) {
|
if (!group) {
|
||||||
@@ -2088,6 +2115,7 @@
|
|||||||
if (sessionId) currentSessionId = sessionId;
|
if (sessionId) currentSessionId = sessionId;
|
||||||
pendingText = '';
|
pendingText = '';
|
||||||
activeToolCalls.clear();
|
activeToolCalls.clear();
|
||||||
|
activeTodoCallTargets.clear();
|
||||||
toolGroupCount = 0;
|
toolGroupCount = 0;
|
||||||
hasGrouped = false;
|
hasGrouped = false;
|
||||||
}
|
}
|
||||||
@@ -2197,7 +2225,7 @@
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试直接解析 JSON
|
// 尝试直接解析 JSON
|
||||||
@@ -2209,7 +2237,7 @@
|
|||||||
bubble.appendChild(createTodoListElement(parsed));
|
bubble.appendChild(createTodoListElement(parsed));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
bubble.innerHTML = renderMarkdown(content);
|
bubble.innerHTML = renderMarkdown(content);
|
||||||
return;
|
return;
|
||||||
@@ -2270,17 +2298,52 @@
|
|||||||
return tool?.kind || tool?.meta?.kind || '';
|
return tool?.kind || tool?.meta?.kind || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function toolTitle(tool) {
|
function normalizeDisplayPath(filePath) {
|
||||||
if (tool?.meta?.title) return tool.meta.title;
|
const rawPath = typeof filePath === 'string' ? filePath.trim() : '';
|
||||||
if (toolKind(tool) === 'file_change') {
|
if (!rawPath) return '';
|
||||||
const filePath = tool?.meta?.subtitle || tool?.input?.file_path || '';
|
const normalizedPath = rawPath.replace(/\\/g, '/');
|
||||||
const action = tool?.input?.new_string && tool?.input?.old_string ? '更新' : '创建';
|
const normalizedCwd = typeof currentCwd === 'string' ? currentCwd.trim().replace(/\\/g, '/') : '';
|
||||||
return filePath ? `${action} ${filePath}` : 'File Change';
|
if (normalizedCwd && normalizedPath.startsWith(`${normalizedCwd}/`)) {
|
||||||
|
return normalizedPath.slice(normalizedCwd.length + 1);
|
||||||
}
|
}
|
||||||
|
return normalizedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileChangeDisplay(tool) {
|
||||||
|
const changes = Array.isArray(tool?.input?.changes) ? tool.input.changes : [];
|
||||||
|
const primaryChange = changes[0] || null;
|
||||||
|
const rawPath = tool?.meta?.subtitle || primaryChange?.path || tool?.input?.path || tool?.input?.file_path || '';
|
||||||
|
const filePath = normalizeDisplayPath(rawPath);
|
||||||
|
const rawKind = primaryChange?.kind || tool?.input?.kind || '';
|
||||||
|
let action = '修改';
|
||||||
|
if (rawKind === 'create' || rawKind === 'new') {
|
||||||
|
action = '创建';
|
||||||
|
} else if (rawKind === 'delete' || rawKind === 'remove') {
|
||||||
|
action = '删除';
|
||||||
|
} else if (rawKind === 'update' || rawKind === 'edit') {
|
||||||
|
action = '更新';
|
||||||
|
} else if (tool?.input?.new_string && tool?.input?.old_string) {
|
||||||
|
action = '更新';
|
||||||
|
}
|
||||||
|
return { action, filePath, changeCount: changes.length };
|
||||||
|
}
|
||||||
|
|
||||||
|
function toolTitle(tool) {
|
||||||
|
if (toolKind(tool) === 'file_change') {
|
||||||
|
const { action, filePath, changeCount } = getFileChangeDisplay(tool);
|
||||||
|
if (filePath && changeCount > 1) return `${action} ${filePath} 等 ${changeCount} 个文件`;
|
||||||
|
if (filePath) return `${action} ${filePath}`;
|
||||||
|
if (changeCount > 1) return `修改 ${changeCount} 个文件`;
|
||||||
|
return tool?.meta?.title || 'File Change';
|
||||||
|
}
|
||||||
|
if (tool?.meta?.title) return tool.meta.title;
|
||||||
return tool?.name || 'Tool';
|
return tool?.name || 'Tool';
|
||||||
}
|
}
|
||||||
|
|
||||||
function toolSubtitle(tool) {
|
function toolSubtitle(tool) {
|
||||||
|
if (toolKind(tool) === 'file_change') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
if (tool?.meta?.subtitle) return tool.meta.subtitle;
|
if (tool?.meta?.subtitle) return tool.meta.subtitle;
|
||||||
if (toolKind(tool) === 'command_execution') {
|
if (toolKind(tool) === 'command_execution') {
|
||||||
return tool?.input?.command || '';
|
return tool?.input?.command || '';
|
||||||
@@ -2357,6 +2420,33 @@
|
|||||||
return section;
|
return section;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isGroupableToolCall(node) {
|
||||||
|
return !!(node?.classList?.contains('tool-call') && node.dataset.toolKind !== 'todo_list');
|
||||||
|
}
|
||||||
|
|
||||||
|
function rememberToolCallTarget(toolUseId, tool, element) {
|
||||||
|
if (!element) return;
|
||||||
|
const entry = activeToolCalls.get(toolUseId);
|
||||||
|
if (entry) {
|
||||||
|
entry.domElement = element;
|
||||||
|
}
|
||||||
|
if (toolKind(tool) === 'todo_list' && tool?.input?.id) {
|
||||||
|
activeTodoCallTargets.set(tool.input.id, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLatestAssistantToolScope() {
|
||||||
|
const streamEl = document.getElementById('streaming-msg');
|
||||||
|
if (streamEl) return streamEl;
|
||||||
|
const agentSelector = `.msg.assistant.agent-${normalizeAgent(currentAgent)}`;
|
||||||
|
const assistantMessages = messagesDiv.querySelectorAll(agentSelector);
|
||||||
|
if (assistantMessages.length > 0) {
|
||||||
|
return assistantMessages[assistantMessages.length - 1];
|
||||||
|
}
|
||||||
|
const fallbackMessages = messagesDiv.querySelectorAll('.msg.assistant');
|
||||||
|
return fallbackMessages.length > 0 ? fallbackMessages[fallbackMessages.length - 1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
function buildMsgElement(m) {
|
function buildMsgElement(m) {
|
||||||
const el = createMsgElement(m.role, m.content, m.attachments || []);
|
const el = createMsgElement(m.role, m.content, m.attachments || []);
|
||||||
if (m.role === 'assistant' && m.toolCalls && m.toolCalls.length > 0) {
|
if (m.role === 'assistant' && m.toolCalls && m.toolCalls.length > 0) {
|
||||||
@@ -2367,7 +2457,7 @@
|
|||||||
const details = createToolCallElement(tc.id || `saved-${Math.random().toString(36).slice(2)}`, tc, true);
|
const details = createToolCallElement(tc.id || `saved-${Math.random().toString(36).slice(2)}`, tc, true);
|
||||||
|
|
||||||
// 散落的 .tool-call 达到 FOLD_AT 个时,移入唯一 .tool-group
|
// 散落的 .tool-call 达到 FOLD_AT 个时,移入唯一 .tool-group
|
||||||
const loose = Array.from(bubble.children).filter(c => c.classList.contains('tool-call'));
|
const loose = Array.from(bubble.children).filter(isGroupableToolCall);
|
||||||
if (loose.length >= FOLD_AT) {
|
if (loose.length >= FOLD_AT) {
|
||||||
let group = bubble.querySelector(':scope > .tool-group');
|
let group = bubble.querySelector(':scope > .tool-group');
|
||||||
if (!group) {
|
if (!group) {
|
||||||
@@ -2390,7 +2480,7 @@
|
|||||||
}
|
}
|
||||||
// 结束时若出现过父目录,收尾散落项
|
// 结束时若出现过父目录,收尾散落项
|
||||||
if (grouped) {
|
if (grouped) {
|
||||||
const loose = Array.from(bubble.children).filter(c => c.classList.contains('tool-call'));
|
const loose = Array.from(bubble.children).filter(isGroupableToolCall);
|
||||||
if (loose.length > 0) {
|
if (loose.length > 0) {
|
||||||
const group = bubble.querySelector(':scope > .tool-group');
|
const group = bubble.querySelector(':scope > .tool-group');
|
||||||
if (group) {
|
if (group) {
|
||||||
@@ -2633,6 +2723,23 @@
|
|||||||
const effectiveInput = tool.input !== undefined ? tool.input : input;
|
const effectiveInput = tool.input !== undefined ? tool.input : input;
|
||||||
const effectiveResult = tool.result;
|
const effectiveResult = tool.result;
|
||||||
const kind = toolKind(tool);
|
const kind = toolKind(tool);
|
||||||
|
|
||||||
|
if (kind === 'todo_list') {
|
||||||
|
let todoData = effectiveInput;
|
||||||
|
// 如果有 result 且是字符串,尝试解析
|
||||||
|
if (effectiveResult && typeof effectiveResult === 'string') {
|
||||||
|
try {
|
||||||
|
todoData = JSON.parse(effectiveResult);
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'tool-call-content todo-list-content';
|
||||||
|
wrapper.appendChild(createTodoListElement(todoData && typeof todoData === 'object' ? todoData : { items: [] }));
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
if (effectiveName === 'AskUserQuestion') {
|
if (effectiveName === 'AskUserQuestion') {
|
||||||
const questions = extractAskUserQuestions(effectiveInput);
|
const questions = extractAskUserQuestions(effectiveInput);
|
||||||
if (questions.length > 0) {
|
if (questions.length > 0) {
|
||||||
@@ -2693,7 +2800,8 @@
|
|||||||
function createToolCallElement(toolUseId, tool, done) {
|
function createToolCallElement(toolUseId, tool, done) {
|
||||||
const details = document.createElement('details');
|
const details = document.createElement('details');
|
||||||
details.className = 'tool-call';
|
details.className = 'tool-call';
|
||||||
details.id = `tool-${toolUseId}`;
|
details.id = `tool-node-${++toolDomSeq}`;
|
||||||
|
details.dataset.toolUseId = toolUseId ? String(toolUseId) : '';
|
||||||
details.dataset.toolName = tool.name || '';
|
details.dataset.toolName = tool.name || '';
|
||||||
if (toolKind(tool)) {
|
if (toolKind(tool)) {
|
||||||
details.dataset.toolKind = toolKind(tool);
|
details.dataset.toolKind = toolKind(tool);
|
||||||
@@ -2728,12 +2836,24 @@
|
|||||||
|
|
||||||
const tool = { id: toolUseId, name, input, kind, meta, done };
|
const tool = { id: toolUseId, name, input, kind, meta, done };
|
||||||
|
|
||||||
|
// 如果是 todo_list,检查是否已存在相同 id 的 todo_list
|
||||||
|
if (kind === 'todo_list' && input?.id) {
|
||||||
|
const existingTodo = findTodoToolCallByTodoId(toolsDiv, input.id);
|
||||||
|
if (existingTodo) {
|
||||||
|
const details = createToolCallElement(toolUseId, tool, done);
|
||||||
|
existingTodo.replaceWith(details);
|
||||||
|
rememberToolCallTarget(toolUseId, tool, details);
|
||||||
|
scrollToBottom();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const details = createToolCallElement(toolUseId, tool, done);
|
const details = createToolCallElement(toolUseId, tool, done);
|
||||||
|
|
||||||
// 折叠策略:只维护唯一一个 .tool-group 父节点
|
// 折叠策略:只维护唯一一个 .tool-group 父节点
|
||||||
// 散落的 .tool-call 直接子节点达到3个时,将它们全部移入父节点;之后继续散落,再达3个再移入
|
// 散落的 .tool-call 直接子节点达到3个时,将它们全部移入父节点;之后继续散落,再达3个再移入
|
||||||
const FOLD_AT = 3;
|
const FOLD_AT = 3;
|
||||||
const looseBefore = Array.from(toolsDiv.children).filter(c => c.classList.contains('tool-call'));
|
const looseBefore = Array.from(toolsDiv.children).filter(isGroupableToolCall);
|
||||||
if (looseBefore.length >= FOLD_AT) {
|
if (looseBefore.length >= FOLD_AT) {
|
||||||
// 确保存在唯一的 .tool-group
|
// 确保存在唯一的 .tool-group
|
||||||
let group = toolsDiv.querySelector(':scope > .tool-group');
|
let group = toolsDiv.querySelector(':scope > .tool-group');
|
||||||
@@ -2754,6 +2874,7 @@
|
|||||||
_refreshGroupSummary(group);
|
_refreshGroupSummary(group);
|
||||||
}
|
}
|
||||||
toolsDiv.appendChild(details);
|
toolsDiv.appendChild(details);
|
||||||
|
rememberToolCallTarget(toolUseId, tool, details);
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2764,23 +2885,71 @@
|
|||||||
if (summary) summary.textContent = `展开 ${count} 个工具调用`;
|
if (summary) summary.textContent = `展开 ${count} 个工具调用`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateToolCall(toolUseId, result) {
|
function findLatestToolCallElement(root, matcher) {
|
||||||
const el = document.getElementById(`tool-${toolUseId}`);
|
if (!root || typeof matcher !== 'function') return null;
|
||||||
if (!el) return;
|
const allTools = root.querySelectorAll('.tool-call');
|
||||||
const tool = activeToolCalls.get(toolUseId) || {
|
for (let i = allTools.length - 1; i >= 0; i--) {
|
||||||
|
const el = allTools[i];
|
||||||
|
if (matcher(el)) return el;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findTodoToolCallByTodoId(root, todoId) {
|
||||||
|
if (!todoId) return null;
|
||||||
|
return findLatestToolCallElement(root, (el) => {
|
||||||
|
if (el.dataset.toolKind !== 'todo_list') return false;
|
||||||
|
const currentTodoId = el.querySelector('.todo-list-container')?.dataset.todoId;
|
||||||
|
return currentTodoId === todoId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateToolCall(toolUseId, result, done = true) {
|
||||||
|
const tool = activeToolCalls.get(toolUseId) || null;
|
||||||
|
const toolUseIdText = toolUseId ? String(toolUseId) : '';
|
||||||
|
const scope = getLatestAssistantToolScope();
|
||||||
|
let el = tool?.domElement && tool.domElement.isConnected ? tool.domElement : null;
|
||||||
|
|
||||||
|
if (!el) {
|
||||||
|
if (tool?.kind === 'todo_list' && tool?.input?.id) {
|
||||||
|
const markedTodo = activeTodoCallTargets.get(tool.input.id);
|
||||||
|
if (markedTodo && markedTodo.isConnected) {
|
||||||
|
el = markedTodo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!el) {
|
||||||
|
el = findLatestToolCallElement(scope, (candidate) => candidate.dataset.toolUseId === toolUseIdText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!el && tool?.kind === 'todo_list' && tool?.input?.id) {
|
||||||
|
el = findTodoToolCallByTodoId(scope, tool.input.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!el) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextTool = tool || {
|
||||||
id: toolUseId,
|
id: toolUseId,
|
||||||
name: el.dataset.toolName || '',
|
name: el.dataset.toolName || '',
|
||||||
kind: el.dataset.toolKind || null,
|
kind: el.dataset.toolKind || null,
|
||||||
done: true,
|
done,
|
||||||
};
|
};
|
||||||
tool.done = true;
|
nextTool.done = done;
|
||||||
if (result !== undefined) tool.result = result;
|
if (result !== undefined) nextTool.result = result;
|
||||||
|
rememberToolCallTarget(toolUseId, nextTool, el);
|
||||||
const summary = el.querySelector('summary');
|
const summary = el.querySelector('summary');
|
||||||
if (summary) applyToolSummary(summary, tool, true);
|
if (summary) applyToolSummary(summary, nextTool, done);
|
||||||
if (tool.name === 'AskUserQuestion') return;
|
if (nextTool.name === 'AskUserQuestion') return;
|
||||||
const nextContent = buildToolContentElement(tool);
|
const nextContent = buildToolContentElement(nextTool);
|
||||||
const content = el.querySelector('.tool-call-content');
|
const content = Array.from(el.children).find((child) => child.tagName !== 'SUMMARY') || null;
|
||||||
if (content) content.replaceWith(nextContent);
|
if (content) {
|
||||||
|
content.replaceWith(nextContent);
|
||||||
|
} else {
|
||||||
|
el.appendChild(nextContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDeleteConfirmMessage(agent) {
|
function getDeleteConfirmMessage(agent) {
|
||||||
|
|||||||
@@ -1221,7 +1221,7 @@ body.session-loading-active {
|
|||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: anchor-center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
@@ -1313,6 +1313,14 @@ body.session-loading-active {
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
background: linear-gradient(180deg, rgba(255, 249, 242, 0.92), rgba(245, 221, 212, 0.32));
|
background: linear-gradient(180deg, rgba(255, 249, 242, 0.92), rgba(245, 221, 212, 0.32));
|
||||||
}
|
}
|
||||||
|
.tool-call-content.todo-list-content {
|
||||||
|
font-family: inherit;
|
||||||
|
white-space: normal;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
.tool-call-content.todo-list-content .todo-list-container {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
.tool-call-content.command,
|
.tool-call-content.command,
|
||||||
.tool-call-content.file-change {
|
.tool-call-content.file-change {
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.94), rgba(250, 246, 240, 0.92));
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.94), rgba(250, 246, 240, 0.92));
|
||||||
@@ -1631,7 +1639,7 @@ body.session-loading-active {
|
|||||||
}
|
}
|
||||||
.input-wrapper {
|
.input-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: anchor-center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
|
|||||||
Reference in New Issue
Block a user