fix: 修复点击退出按钮没有中断的问题;兼容了工具调用中断后过滤一遍message;

This commit is contained in:
肖应宇 2026-03-23 10:23:09 +08:00
parent e4c31b3b1e
commit b97e96d29e
2 changed files with 61 additions and 10 deletions

View File

@ -504,10 +504,15 @@ export default function ChatPage() {
<Button <Button
className="w-full bg-[#f9f8fa] hover:bg-[#8E47F0] hover:text-white" className="w-full bg-[#f9f8fa] hover:bg-[#8E47F0] hover:text-white"
variant="ghost" variant="ghost"
onClick={() => { onClick={async () => {
// 如果正在生成,先终止再退出
if (thread.isLoading) {
await handleStop();
}
setShowExitDialog(false); setShowExitDialog(false);
router.push("/workspace/chats/new"); // 使用完整页面刷新确保组件重新挂载isNewThread 为 true
}} window.location.href = "/workspace/chats/new";
}}
> >
</Button> </Button>

View File

@ -33,9 +33,47 @@ export function groupMessages<T>(
if (messages.length === 0) { if (messages.length === 0) {
return []; return [];
} }
// 预处理:收集所有 ToolMessage 的 tool_call_id
const toolMessageIds = new Set<string>();
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<string>();
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[] = []; const groups: MessageGroup[] = [];
for (const message of messages) { for (const message of filteredMessages) {
const lastGroup = groups[groups.length - 1]; const lastGroup = groups[groups.length - 1];
if (message.type === "human") { if (message.type === "human") {
groups.push({ groups.push({
@ -44,9 +82,9 @@ export function groupMessages<T>(
messages: [message], messages: [message],
}); });
} else if (message.type === "tool") { } else if (message.type === "tool") {
// Check if this is a clarification tool message // 检查是否为澄清问题的工具消息
if (isClarificationToolMessage(message)) { if (isClarificationToolMessage(message)) {
// Add to processing group if available (to maintain tool call association) // 如果有可用的处理组,添加到其中(保持工具调用关联)
if ( if (
lastGroup && lastGroup &&
lastGroup.type !== "human" && lastGroup.type !== "human" &&
@ -55,7 +93,7 @@ export function groupMessages<T>(
) { ) {
lastGroup.messages.push(message); lastGroup.messages.push(message);
} }
// Also create a separate clarification group for prominent display // 同时创建单独的澄清组以便突出显示
groups.push({ groups.push({
id: message.id, id: message.id,
type: "assistant:clarification", type: "assistant:clarification",
@ -69,9 +107,17 @@ export function groupMessages<T>(
) { ) {
lastGroup.messages.push(message); lastGroup.messages.push(message);
} else { } 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") { } else if (message.type === "ai") {
if (hasReasoning(message) || hasToolCalls(message)) { if (hasReasoning(message) || hasToolCalls(message)) {
@ -100,7 +146,7 @@ export function groupMessages<T>(
currentGroup.messages.push(message); currentGroup.messages.push(message);
} else { } else {
throw new Error( throw new Error(
"Assistant message with reasoning or tool calls must be preceded by a processing group", "带有推理或工具调用的 AI 消息必须位于处理组之后",
); );
} }
} }