fix: AI消息时间戳显示、工具调用卡片恢复
1. 修复AI回复消息不显示时间戳的问题:updateLastAssistantMessage 新增 timestamp 参数 2. 恢复工具调用卡片显示(工具名称+参数,不显示执行结果):updateLastAssistantMessage 新增 toolCalls 参数 3. 根因:流式消息通过 updateLastAssistantMessage 更新 DOM,但该函数未渲染时间戳和工具卡片, 而 renderMessages 因 placeholder 已被计数而跳过 appendMessageDOM
This commit is contained in:
@@ -260,7 +260,10 @@ function renderToolCallCard(tc: ToolCallRecord): string {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateLastAssistantMessage(content: string, think: string | null, _stats: unknown, model?: string): void {
|
export function updateLastAssistantMessage(
|
||||||
|
content: string, think: string | null, _stats: unknown, model?: string,
|
||||||
|
timestamp?: number, toolCalls?: ToolCallRecord[]
|
||||||
|
): void {
|
||||||
const lastMsg = currentPlaceholder;
|
const lastMsg = currentPlaceholder;
|
||||||
if (!lastMsg) return;
|
if (!lastMsg) return;
|
||||||
|
|
||||||
@@ -307,6 +310,45 @@ export function updateLastAssistantMessage(content: string, think: string | null
|
|||||||
thinkBlock.querySelector('pre')!.textContent = think;
|
thinkBlock.querySelector('pre')!.textContent = think;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 工具调用历史记录(可折叠)──
|
||||||
|
if (toolCalls && toolCalls.length > 0) {
|
||||||
|
let existingHistory = lastMsg.querySelector('.tool-calls-history');
|
||||||
|
if (existingHistory) existingHistory.remove();
|
||||||
|
|
||||||
|
const tcCount = toolCalls.length;
|
||||||
|
const successCount = toolCalls.filter(t => t.status === 'success').length;
|
||||||
|
const errorCount = toolCalls.filter(t => t.status === 'error').length;
|
||||||
|
|
||||||
|
const historyDiv = document.createElement('div');
|
||||||
|
historyDiv.className = 'tool-calls-history';
|
||||||
|
historyDiv.innerHTML = `
|
||||||
|
<div class="tool-calls-toggle" onclick="this.parentElement.classList.toggle('expanded')">
|
||||||
|
<span class="tool-calls-chevron">▸</span>
|
||||||
|
<span class="tool-calls-summary">🔧 ${tcCount} 个工具调用(✅${successCount} ❌${errorCount})</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool-calls-list">
|
||||||
|
${toolCalls.map(tc => renderToolCallCard(tc)).join('')}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
const msgBody = lastMsg.querySelector('.msg-body');
|
||||||
|
if (msgBody) {
|
||||||
|
const refNode = contentDiv?.nextSibling || null;
|
||||||
|
msgBody.insertBefore(historyDiv, refNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 时间戳 ──
|
||||||
|
if (timestamp) {
|
||||||
|
let statsDiv = lastMsg.querySelector('.msg-stats');
|
||||||
|
if (!statsDiv) {
|
||||||
|
statsDiv = document.createElement('div');
|
||||||
|
statsDiv.className = 'msg-stats';
|
||||||
|
const msgBody = lastMsg.querySelector('.msg-body');
|
||||||
|
if (msgBody) msgBody.appendChild(statsDiv);
|
||||||
|
}
|
||||||
|
statsDiv.innerHTML = `<span>${formatTime(timestamp)}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ async function handleRetry(): Promise<void> {
|
|||||||
...s, messages: [...s.messages, lastMsg], updatedAt: Date.now()
|
...s, messages: [...s.messages, lastMsg], updatedAt: Date.now()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
updateLastAssistantMessage(finalContent, retryThinkContent || null, loopStats || null);
|
updateLastAssistantMessage(finalContent, retryThinkContent || null, loopStats || null, undefined, Date.now(), toolRecords?.length ? toolRecords : undefined);
|
||||||
} else {
|
} else {
|
||||||
const assistantMsg: ChatMessage = {
|
const assistantMsg: ChatMessage = {
|
||||||
role: 'assistant', content: finalContent || '', timestamp: Date.now(),
|
role: 'assistant', content: finalContent || '', timestamp: Date.now(),
|
||||||
@@ -369,7 +369,7 @@ async function handleRetry(): Promise<void> {
|
|||||||
state.update(KEYS.CURRENT_SESSION, (s: ChatSession | null) => ({
|
state.update(KEYS.CURRENT_SESSION, (s: ChatSession | null) => ({
|
||||||
...s, messages: [...s.messages, assistantMsg], updatedAt: Date.now()
|
...s, messages: [...s.messages, assistantMsg], updatedAt: Date.now()
|
||||||
}));
|
}));
|
||||||
updateLastAssistantMessage(finalContent, retryThinkContent || null, loopStats || null);
|
updateLastAssistantMessage(finalContent, retryThinkContent || null, loopStats || null, undefined, Date.now(), toolRecords?.length ? toolRecords : undefined);
|
||||||
}
|
}
|
||||||
renderMessages();
|
renderMessages();
|
||||||
await saveCurrentSession();
|
await saveCurrentSession();
|
||||||
@@ -749,7 +749,9 @@ export async function sendMessage(): Promise<void> {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
if (finalStats) {
|
if (finalStats) {
|
||||||
updateLastAssistantMessage(assistantContent, thinkContent || null, finalStats, modelName || undefined);
|
updateLastAssistantMessage(assistantContent, thinkContent || null, finalStats, modelName || undefined, Date.now());
|
||||||
|
} else {
|
||||||
|
updateLastAssistantMessage(assistantContent, thinkContent || null, null, modelName || undefined, Date.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
await saveCurrentSession();
|
await saveCurrentSession();
|
||||||
@@ -1067,7 +1069,7 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
|
|||||||
updatedAt: Date.now()
|
updatedAt: Date.now()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
updateLastAssistantMessage(assistantContent, thinkContent || null, loopStats || null);
|
updateLastAssistantMessage(assistantContent, thinkContent || null, loopStats || null, undefined, Date.now(), toolRecords?.length ? toolRecords : undefined);
|
||||||
} else {
|
} else {
|
||||||
// 单迭代模式:正常保存
|
// 单迭代模式:正常保存
|
||||||
const assistantMsg: ChatMessage = {
|
const assistantMsg: ChatMessage = {
|
||||||
@@ -1085,7 +1087,7 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
|
|||||||
messages: [...session.messages, assistantMsg],
|
messages: [...session.messages, assistantMsg],
|
||||||
updatedAt: Date.now()
|
updatedAt: Date.now()
|
||||||
}));
|
}));
|
||||||
updateLastAssistantMessage(assistantContent, thinkContent || null, loopStats || null);
|
updateLastAssistantMessage(assistantContent, thinkContent || null, loopStats || null, undefined, Date.now(), toolRecords?.length ? toolRecords : undefined);
|
||||||
}
|
}
|
||||||
renderMessages();
|
renderMessages();
|
||||||
await saveCurrentSession();
|
await saveCurrentSession();
|
||||||
|
|||||||
Reference in New Issue
Block a user