diff --git a/docs/chat-chain-changes/2026-11-05-thinking-avatar.md b/docs/chat-chain-changes/2026-11-05-thinking-avatar.md new file mode 100644 index 0000000..6004fbf --- /dev/null +++ b/docs/chat-chain-changes/2026-11-05-thinking-avatar.md @@ -0,0 +1,9 @@ +--- +date: 2026-11-05 +pr: pending +feature: Animated application logo while thinking +impact: The thinking indicator uses the application logo with a gentle animation, disabled when reduced motion is requested. Chat behavior is unchanged. +--- + +The thinking indicator no longer uses the old character GIF. The new animation +is applied to the existing application logo without changing chat events. diff --git a/packages/client/src/components/hermes/chat/MessageList.vue b/packages/client/src/components/hermes/chat/MessageList.vue index 4a55d50..98be76c 100644 --- a/packages/client/src/components/hermes/chat/MessageList.vue +++ b/packages/client/src/components/hermes/chat/MessageList.vue @@ -21,7 +21,6 @@ import VirtualMessageList from "./VirtualMessageList.vue"; import MessageItem from "./MessageItem.vue"; import { groupRunMessages } from "./groupRunMessages"; import { LIVE_CHAT_MAX_LOADED_MESSAGES, useChatStore, type Message } from "@/stores/hermes/chat"; -import thinkingImage from "@/assets/thinking.gif"; import { useToolTraceVisibility } from "@/composables/useToolTraceVisibility"; const chatStore = useChatStore(); @@ -527,7 +526,7 @@ defineExpose({
{ + await authenticate(page, TEST_ACCESS_KEY, 'research') + await mockHermesApi(page) + await mockChatSocket(page) + await page.goto('/#/hermes/chat') + await sendChatMessage(page, 'think') + const { sessionId } = await waitForRunSessionId(page) + await page.evaluate((sid) => { + (window as any).__PW_CHAT_SOCKET__.latest.__trigger('run.started', { event: 'run.started', session_id: sid, run_id: 'thinking-logo' }) + }, sessionId) + const avatar = page.locator('.thinking-avatar') + await expect(avatar).toBeVisible() + await expect(avatar).toHaveAttribute('src', '/app-logo.png') + await expect(avatar).toHaveCSS('animation-name', /^thinking-avatar-breathe/) + await page.emulateMedia({ reducedMotion: 'reduce' }) + await expect(avatar).toHaveCSS('animation-name', 'none') + await expect(page.locator('.thinking-status-label')).toHaveCSS('animation-name', 'none') +}) + test('opens the session model dialog and the session search from the chat header', async ({ page }) => { await authenticate(page, TEST_ACCESS_KEY, 'research') await mockHermesApi(page, { sessions: [sampleSession] })