From 603f2a1e5aca393a24091131cb1e7d5ff743a135 Mon Sep 17 00:00:00 2001 From: Wu Yue Date: Wed, 30 Jul 2025 14:44:44 +0800 Subject: [PATCH] fix(core): ai message resending (#13359) Close [AI-395](https://linear.app/affine-design/issue/AI-395) ## Summary by CodeRabbit * **Bug Fixes** * Improved chat stability by resetting chat action signals after processing to prevent repeated triggers. * **New Features** * Added end-to-end tests for new chat session creation and chat pinning functionality to enhance reliability. * **Enhancements** * Enhanced chat toolbar with test identifiers and pinned state attributes for better accessibility and testing. Co-authored-by: fengmk2 --- .../ai-chat-content/ai-chat-content.ts | 1 + .../components/ai-chat-input/ai-chat-input.ts | 1 + .../ai-chat-toolbar/ai-chat-toolbar.ts | 8 +- .../e2e/basic/chat.spec.ts | 85 +++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts index edb86fb46..812b4596d 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts @@ -391,6 +391,7 @@ export class AIChatContent extends SignalWatcher( }) .catch(console.error); } + AIProvider.slots.requestOpenWithChat.next(null); } ) ); diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/ai-chat-input.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/ai-chat-input.ts index 2093c0eec..948b21e3a 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/ai-chat-input.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/ai-chat-input.ts @@ -405,6 +405,7 @@ export class AIChatInput extends SignalWatcher( this.send(input).catch(console.error); }, 0); } + AIProvider.slots.requestSendWithChat.next(null); } ) ); diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-toolbar/ai-chat-toolbar.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-toolbar/ai-chat-toolbar.ts index c6a5ff8aa..26e21265e 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-toolbar/ai-chat-toolbar.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-toolbar/ai-chat-toolbar.ts @@ -92,14 +92,20 @@ export class AIChatToolbar extends WithDisposable(ShadowlessElement) { const pinned = this.session?.pinned; return html`
-
+
${PlusIcon()} New Chat
${pinned ? PinedIcon() : PinIcon()} diff --git a/tests/affine-cloud-copilot/e2e/basic/chat.spec.ts b/tests/affine-cloud-copilot/e2e/basic/chat.spec.ts index 637f98648..afb0dae44 100644 --- a/tests/affine-cloud-copilot/e2e/basic/chat.spec.ts +++ b/tests/affine-cloud-copilot/e2e/basic/chat.spec.ts @@ -450,4 +450,89 @@ test.describe('AIBasic/Chat', () => { }, ]); }); + + test('should support create a new chat after ask ai', async ({ + loggedInPage: page, + utils, + }) => { + await utils.chatPanel.closeChatPanel(page); + await utils.editor.askAIWithText( + page, + 'AFFiNE is an open source all in one workspace.' + ); + await page.keyboard.type('Translate to chinese.'); + + const sendButton = await page.getByTestId('ai-panel-input-send'); + await expect(sendButton).toHaveAttribute('data-active', 'true'); + await sendButton.click(); + + await expect(page.getByTestId('sidebar-tab-content-chat')).toBeVisible(); + await utils.chatPanel.waitForHistory(page, [ + { + role: 'user', + content: + 'AFFiNE is an open source all in one workspace.\nTranslate to chinese.', + }, + { + role: 'assistant', + status: 'success', + }, + ]); + + await page.getByTestId('ai-panel-new-chat').click(); + await page.waitForTimeout(1000); + await utils.chatPanel.expectToHaveHistory(page, []); + }); + + test('should support pin chat', async ({ loggedInPage: page, utils }) => { + await utils.chatPanel.openChatPanel(page); + await utils.chatPanel.makeChat( + page, + 'Hello, how can you help me? Answer in 50 words.' + ); + + await utils.chatPanel.waitForHistory(page, [ + { + role: 'user', + content: 'Hello, how can you help me? Answer in 50 words.', + }, + { + role: 'assistant', + status: 'success', + }, + ]); + + // pinned + await expect(page.getByTestId('ai-panel-pin-chat')).toHaveAttribute( + 'data-pinned', + 'false' + ); + await page.getByTestId('ai-panel-pin-chat').click(); + await expect(page.getByTestId('ai-panel-pin-chat')).toHaveAttribute( + 'data-pinned', + 'true' + ); + + // create new doc + await utils.editor.createDoc(page, 'Doc 1', 'doc1'); + await utils.chatPanel.expectToHaveHistory(page, [ + { + role: 'user', + content: 'Hello, how can you help me? Answer in 50 words.', + }, + { + role: 'assistant', + status: 'idle', + }, + ]); + await page.getByTestId('ai-panel-pin-chat').click(); + + // unpinned + await expect(page.getByTestId('ai-panel-pin-chat')).toHaveAttribute( + 'data-pinned', + 'false' + ); + await utils.editor.createDoc(page, 'Doc 2', 'doc2'); + await utils.chatPanel.expectToHaveHistory(page, []); + }); });