diff --git a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte
index 8aa3a9f4e0..0078225c08 100644
--- a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte
+++ b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessages.svelte
@@ -237,48 +237,76 @@
});
-
- {#each displayMessages as { isLastAssistantMessage, isLastUserMessage, message, nextAssistantMessage, siblingInfo, toolMessages } (message.id)}
-
- {/each}
-
- {#if conversationsStore.activeConversation && agenticStore.getPendingSteeringMessageContent(conversationsStore.activeConversation!.id)}
- {@const convId = conversationsStore.activeConversation!.id}
- {@const pendingContent = agenticStore.getPendingSteeringMessageContent(convId)}
-
- {#if pendingContent}
-
agenticStore.clearSteeringMessage(convId)}
- onEdit={(newContent, extras) =>
- agenticStore.injectSteeringMessage(convId, newContent, extras)}
- onSendImmediately={() => chatStore.abortCurrentFlow(convId)}
+
+{#key conversationsStore.activeConversation?.id ?? 'new'}
+
+ {#each displayMessages as { isLastAssistantMessage, isLastUserMessage, message, nextAssistantMessage, siblingInfo, toolMessages } (message.id)}
+
- {/if}
- {:else if conversationsStore.activeConversation && chatStore.getPendingMessageContent(conversationsStore.activeConversation!.id)}
- {@const convId = conversationsStore.activeConversation!.id}
- {@const pendingContent = chatStore.getPendingMessageContent(convId)}
+ {/each}
- {#if pendingContent}
- chatStore.clearPendingMessage(convId)}
- onEdit={(newContent, extras) => chatStore.injectPendingMessage(convId, newContent, extras)}
- onSendImmediately={() => chatStore.abortCurrentFlow(convId)}
- />
+ {#if conversationsStore.activeConversation && agenticStore.getPendingSteeringMessageContent(conversationsStore.activeConversation!.id)}
+ {@const convId = conversationsStore.activeConversation!.id}
+ {@const pendingContent = agenticStore.getPendingSteeringMessageContent(convId)}
+
+ {#if pendingContent}
+ agenticStore.clearSteeringMessage(convId)}
+ onEdit={(newContent, extras) =>
+ agenticStore.injectSteeringMessage(convId, newContent, extras)}
+ onSendImmediately={() => chatStore.abortCurrentFlow(convId)}
+ />
+ {/if}
+ {:else if conversationsStore.activeConversation && chatStore.getPendingMessageContent(conversationsStore.activeConversation!.id)}
+ {@const convId = conversationsStore.activeConversation!.id}
+ {@const pendingContent = chatStore.getPendingMessageContent(convId)}
+
+ {#if pendingContent}
+ chatStore.clearPendingMessage(convId)}
+ onEdit={(newContent, extras) =>
+ chatStore.injectPendingMessage(convId, newContent, extras)}
+ onSendImmediately={() => chatStore.abortCurrentFlow(convId)}
+ />
+ {/if}
{/if}
- {/if}
-
+
+{/key}
+
+
diff --git a/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte b/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte
index 3ad3f24685..6cea95d0d0 100644
--- a/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte
+++ b/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte
@@ -315,13 +315,18 @@
bottomed move with transform, not bottom:
+ // layout-property transitions need the main thread every frame and
+ // stutter while a long conversation loads; transform transitions
+ // run on the compositor and stay smooth
+ 'pointer-events-none md:sticky fixed mt-auto transition-transform duration-200',
deviceStore.isStandalone
? 'bottom-6 right-4 left-4'
: deviceStore.isIOSSafari
? 'bottom-1 left-2 right-2'
: 'bottom-2 right-2 left-2',
- isEmpty ? 'md:bottom-[calc(50dvh-7rem)] 2xl:bottom-[calc(50dvh-4rem)]' : 'md:bottom-4'
+ 'md:bottom-4',
+ isEmpty ? 'md:translate-y-[calc(-50dvh+8rem)] 2xl:translate-y-[calc(-50dvh+5rem)]' : ''
]}
>