fix: 会话快速切换pollute message
This commit is contained in:
+97
@@ -327,6 +327,103 @@ describe('useEditorAgentConversation', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('does not apply a completed message response after switching conversations', async () => {
|
||||
const client = createClient();
|
||||
const onCanvasRefreshRequested = vi.fn();
|
||||
let resolveSend!: (response: EditorAgentMessageResponse) => void;
|
||||
vi.mocked(client.sendMessage).mockImplementation(
|
||||
() =>
|
||||
new Promise<EditorAgentMessageResponse>((resolve) => {
|
||||
resolveSend = resolve;
|
||||
}),
|
||||
);
|
||||
const { result } = renderHook(() =>
|
||||
useEditorAgentConversation({
|
||||
projectId: 'project-1',
|
||||
client,
|
||||
onCanvasRefreshRequested,
|
||||
}),
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.activeConversationId).toBe('conversation-1');
|
||||
});
|
||||
|
||||
let sendPromise!: Promise<void>;
|
||||
act(() => {
|
||||
sendPromise = result.current.sendMessage('在第一个会话生成图片');
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(result.current.isWaiting).toBe(true);
|
||||
});
|
||||
|
||||
vi.mocked(client.getConversation).mockResolvedValueOnce({
|
||||
conversationId: 'conversation-2',
|
||||
projectId: 'project-1',
|
||||
title: '第二个会话',
|
||||
messages: [
|
||||
{
|
||||
id: 20,
|
||||
role: 'assistant',
|
||||
text: '第二个会话原有消息',
|
||||
attachments: [],
|
||||
toolCall: null,
|
||||
createdAt: '2026-07-03T00:02:00.000Z',
|
||||
},
|
||||
],
|
||||
createdAt: '2026-07-03T00:02:00.000Z',
|
||||
updatedAt: '2026-07-03T00:02:00.000Z',
|
||||
});
|
||||
await act(async () => {
|
||||
await result.current.selectConversation('conversation-2');
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
resolveSend({
|
||||
conversation: {
|
||||
conversationId: 'conversation-1',
|
||||
projectId: 'project-1',
|
||||
title: '第一个会话已更新',
|
||||
updatedAt: '2026-07-03T00:03:00.000Z',
|
||||
},
|
||||
deltaMessages: [
|
||||
{
|
||||
id: 21,
|
||||
role: 'assistant',
|
||||
text: '第一个会话生成完成',
|
||||
attachments: [],
|
||||
toolCall: {
|
||||
toolName: 'generate_image',
|
||||
status: 'completed',
|
||||
externalJobId: 'task-conversation-1',
|
||||
args: {},
|
||||
displayArgs: {
|
||||
stringArgs: [],
|
||||
imageArgs: [],
|
||||
extras: { priceMudPoints: 0 },
|
||||
},
|
||||
images: [{ imageSrc: '/conversation-1-result.png' }],
|
||||
error: null,
|
||||
},
|
||||
createdAt: '2026-07-03T00:03:00.000Z',
|
||||
},
|
||||
],
|
||||
errorMessage: null,
|
||||
});
|
||||
await sendPromise;
|
||||
});
|
||||
|
||||
expect(result.current.activeConversationId).toBe('conversation-2');
|
||||
expect(result.current.messages).toHaveLength(1);
|
||||
expect(result.current.messages[0]?.text).toBe('第二个会话原有消息');
|
||||
expect(onCanvasRefreshRequested).not.toHaveBeenCalled();
|
||||
expect(
|
||||
result.current.conversations.find(
|
||||
(conversation) => conversation.conversationId === 'conversation-1',
|
||||
)?.title,
|
||||
).toBe('第一个会话已更新');
|
||||
});
|
||||
|
||||
it('creates a conversation before sending when the project has no history', async () => {
|
||||
const client = createClient();
|
||||
vi.mocked(client.listConversations).mockResolvedValueOnce([]);
|
||||
|
||||
@@ -189,6 +189,7 @@ export function useEditorAgentConversation({
|
||||
|
||||
const applyConversationDetail = useCallback(
|
||||
(detail: EditorAgentConversationDetail) => {
|
||||
activeConversationIdRef.current = detail.conversationId;
|
||||
setConversations((currentConversations) =>
|
||||
upsertConversationSummary(
|
||||
currentConversations,
|
||||
@@ -240,6 +241,7 @@ export function useEditorAgentConversation({
|
||||
setIsLoadingMessages(false);
|
||||
if (!normalizedProjectId) {
|
||||
setConversations([]);
|
||||
activeConversationIdRef.current = null;
|
||||
setActiveConversationId(null);
|
||||
setMessages([]);
|
||||
setErrorMessage(null);
|
||||
@@ -259,6 +261,7 @@ export function useEditorAgentConversation({
|
||||
setConversations(sortedConversations);
|
||||
const firstConversation = sortedConversations[0] ?? null;
|
||||
if (!firstConversation) {
|
||||
activeConversationIdRef.current = null;
|
||||
setActiveConversationId(null);
|
||||
setMessages([]);
|
||||
return;
|
||||
@@ -413,6 +416,9 @@ export function useEditorAgentConversation({
|
||||
response.conversation,
|
||||
),
|
||||
);
|
||||
if (activeConversationIdRef.current !== conversationId) {
|
||||
return;
|
||||
}
|
||||
if (response.errorMessage) {
|
||||
setErrorMessage(response.errorMessage);
|
||||
} else {
|
||||
@@ -424,10 +430,12 @@ export function useEditorAgentConversation({
|
||||
}
|
||||
const message =
|
||||
error instanceof Error ? error.message : '发送画布 Agent 消息失败';
|
||||
setErrorMessage(message);
|
||||
setMessages((currentMessages) =>
|
||||
currentMessages.filter((message) => message !== optimisticMessage),
|
||||
);
|
||||
if (activeConversationIdRef.current === conversationId) {
|
||||
setErrorMessage(message);
|
||||
setMessages((currentMessages) =>
|
||||
currentMessages.filter((message) => message !== optimisticMessage),
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
if (activeRequestAbortControllerRef.current === abortController) {
|
||||
@@ -532,6 +540,7 @@ export function useEditorAgentConversation({
|
||||
await loadConversation(nextConversation.conversationId);
|
||||
return;
|
||||
}
|
||||
activeConversationIdRef.current = null;
|
||||
setActiveConversationId(null);
|
||||
setMessages([]);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user