From b97e96d29eb17f8a239f406e8a2bfa394fe01b1d Mon Sep 17 00:00:00 2001
From: MT-Mint <798521692@qq.com>
Date: Mon, 23 Mar 2026 10:23:09 +0800
Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=82=B9=E5=87=BB?=
=?UTF-8?q?=E9=80=80=E5=87=BA=E6=8C=89=E9=92=AE=E6=B2=A1=E6=9C=89=E4=B8=AD?=
=?UTF-8?q?=E6=96=AD=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=9B=E5=85=BC=E5=AE=B9?=
=?UTF-8?q?=E4=BA=86=E5=B7=A5=E5=85=B7=E8=B0=83=E7=94=A8=E4=B8=AD=E6=96=AD?=
=?UTF-8?q?=E5=90=8E=E8=BF=87=E6=BB=A4=E4=B8=80=E9=81=8Dmessage=EF=BC=9B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../app/workspace/chats/[thread_id]/page.tsx | 11 +++-
frontend/src/core/messages/utils.ts | 60 ++++++++++++++++---
2 files changed, 61 insertions(+), 10 deletions(-)
diff --git a/frontend/src/app/workspace/chats/[thread_id]/page.tsx b/frontend/src/app/workspace/chats/[thread_id]/page.tsx
index 750bc1d6..e7bc36cf 100644
--- a/frontend/src/app/workspace/chats/[thread_id]/page.tsx
+++ b/frontend/src/app/workspace/chats/[thread_id]/page.tsx
@@ -504,10 +504,15 @@ export default function ChatPage() {
diff --git a/frontend/src/core/messages/utils.ts b/frontend/src/core/messages/utils.ts
index d73417db..92951ca6 100644
--- a/frontend/src/core/messages/utils.ts
+++ b/frontend/src/core/messages/utils.ts
@@ -33,9 +33,47 @@ export function groupMessages(
if (messages.length === 0) {
return [];
}
+
+ // 预处理:收集所有 ToolMessage 的 tool_call_id
+ const toolMessageIds = new Set();
+ for (const message of messages) {
+ if (message.type === "tool" && message.tool_call_id) {
+ toolMessageIds.add(message.tool_call_id);
+ }
+ }
+
+ // 预处理:检查哪些 tool_calls 没有对应的响应
+ const danglingToolCallIds = new Set();
+ for (const message of messages) {
+ if (message.type === "ai" && message.tool_calls) {
+ for (const tc of message.tool_calls) {
+ const tcId = tc.id;
+ if (tcId && !toolMessageIds.has(tcId)) {
+ danglingToolCallIds.add(tcId);
+ }
+ }
+ }
+ }
+
+ // 过滤掉只有悬空 tool_calls 且没有其他内容的 AI 消息
+ const filteredMessages = messages.filter((message) => {
+ if (message.type === "ai" && hasToolCalls(message)) {
+ // 检查是否所有 tool_calls 都是悬空的
+ const allDangling = message.tool_calls?.every((tc) =>
+ danglingToolCallIds.has(tc.id!),
+ );
+ // 如果全部悬空且没有其他内容,跳过该消息
+ if (allDangling && !hasReasoning(message) && !hasContent(message)) {
+ console.warn("过滤只有悬空 tool_calls 的 AI 消息:", message.id);
+ return false;
+ }
+ }
+ return true;
+ });
+
const groups: MessageGroup[] = [];
- for (const message of messages) {
+ for (const message of filteredMessages) {
const lastGroup = groups[groups.length - 1];
if (message.type === "human") {
groups.push({
@@ -44,9 +82,9 @@ export function groupMessages(
messages: [message],
});
} else if (message.type === "tool") {
- // Check if this is a clarification tool message
+ // 检查是否为澄清问题的工具消息
if (isClarificationToolMessage(message)) {
- // Add to processing group if available (to maintain tool call association)
+ // 如果有可用的处理组,添加到其中(保持工具调用关联)
if (
lastGroup &&
lastGroup.type !== "human" &&
@@ -55,7 +93,7 @@ export function groupMessages(
) {
lastGroup.messages.push(message);
}
- // Also create a separate clarification group for prominent display
+ // 同时创建单独的澄清组以便突出显示
groups.push({
id: message.id,
type: "assistant:clarification",
@@ -69,9 +107,17 @@ export function groupMessages(
) {
lastGroup.messages.push(message);
} else {
- throw new Error(
- "Tool message must be matched with a previous assistant message with tool calls",
+ // 悬空的工具消息(如生成被中断导致)
+ // 创建独立的处理组以便显示
+ console.warn(
+ "检测到悬空的工具消息,创建独立组:",
+ message.tool_call_id,
);
+ groups.push({
+ id: message.id,
+ type: "assistant:processing",
+ messages: [message],
+ });
}
} else if (message.type === "ai") {
if (hasReasoning(message) || hasToolCalls(message)) {
@@ -100,7 +146,7 @@ export function groupMessages(
currentGroup.messages.push(message);
} else {
throw new Error(
- "Assistant message with reasoning or tool calls must be preceded by a processing group",
+ "带有推理或工具调用的 AI 消息必须位于处理组之后",
);
}
}