diff --git a/application/single_app/static/js/chat/chat-conversations.js b/application/single_app/static/js/chat/chat-conversations.js
index 4380ffa0..77dd90e6 100644
--- a/application/single_app/static/js/chat/chat-conversations.js
+++ b/application/single_app/static/js/chat/chat-conversations.js
@@ -111,6 +111,21 @@ async function refreshAgentsAndModelsForActiveConversation() {
await refreshAgentsForActiveConversation();
await refreshModelSelection();
}
+
+function scrollConversationViewToBottom() {
+ const container = document.getElementById("chat-messages-container") || document.getElementById("chatbox");
+ if (!container) {
+ return;
+ }
+ // Use animation frames so layout-dependent heights settle first.
+ requestAnimationFrame(() => {
+ container.scrollTop = container.scrollHeight;
+ requestAnimationFrame(() => {
+ container.scrollTop = container.scrollHeight;
+ });
+ });
+}
+
let selectionModeActive = false; // Track if selection mode is active
let selectionModeTimer = null; // Timer for auto-hiding checkboxes
let showHiddenConversations = false; // Track if hidden conversations should be shown
@@ -1670,6 +1685,8 @@ export async function selectConversation(conversationId) {
}
if (isCollaborativeConversation && window.chatCollaboration?.activateConversation) {
+ await loadMessages(conversationId);
+ scrollConversationViewToBottom();
await window.chatCollaboration.activateConversation(conversationId, metadata);
} else {
window.chatCollaboration?.deactivateConversation?.();
@@ -1677,6 +1694,7 @@ export async function selectConversation(conversationId) {
try {
const streamingModule = await import('./chat-streaming.js');
await streamingModule.reattachStreamingConversation(conversationId);
+ scrollConversationViewToBottom();
} catch (error) {
console.warn('Failed to reattach active stream for conversation:', error);
}
diff --git a/application/single_app/static/js/chat/chat-global.js b/application/single_app/static/js/chat/chat-global.js
index 0cb42f72..7ea874a4 100644
--- a/application/single_app/static/js/chat/chat-global.js
+++ b/application/single_app/static/js/chat/chat-global.js
@@ -9,9 +9,71 @@ let groupPrompts = [];
let publicPrompts = [];
let currentlyEditingId = null;
+function getChatScrollContainer() {
+ return (
+ document.getElementById("chat-messages-container") ||
+ document.getElementById("chatbox") ||
+ null
+ );
+}
+
+function isChatNearBottom(threshold = 40) {
+ const container = getChatScrollContainer();
+ if (!container) return true;
+
+ const distanceFromBottom =
+ container.scrollHeight - (container.scrollTop + container.clientHeight);
+ return distanceFromBottom <= threshold;
+}
+
function scrollChatToBottom() {
- const chatbox = document.getElementById("chatbox");
- if (chatbox) {
- chatbox.scrollTop = chatbox.scrollHeight;
+ const container = getChatScrollContainer();
+ if (container) {
+ container.scrollTop = container.scrollHeight;
}
-}
\ No newline at end of file
+}
+
+function showScrollToBottomButton() {
+ const btn = document.getElementById("scroll-to-bottom-btn");
+ if (!btn) return;
+ btn.classList.remove("d-none");
+}
+
+function hideScrollToBottomButton() {
+ const btn = document.getElementById("scroll-to-bottom-btn");
+ if (!btn) return;
+ btn.classList.add("d-none");
+}
+
+function initializeChatScrollBehavior() {
+ const container = getChatScrollContainer();
+ const btn = document.getElementById("scroll-to-bottom-btn");
+
+ if (!container) return;
+
+ // Initial state
+ if (isChatNearBottom()) {
+ hideScrollToBottomButton();
+ } else {
+ showScrollToBottomButton();
+ }
+
+ container.addEventListener("scroll", () => {
+ if (isChatNearBottom()) {
+ hideScrollToBottomButton();
+ } else {
+ showScrollToBottomButton();
+ }
+ });
+
+ if (btn) {
+ btn.addEventListener("click", () => {
+ scrollChatToBottom();
+ hideScrollToBottomButton();
+ });
+ }
+}
+
+window.addEventListener("load", () => {
+ initializeChatScrollBehavior();
+});
\ No newline at end of file
diff --git a/application/single_app/static/js/chat/chat-messages.js b/application/single_app/static/js/chat/chat-messages.js
index 1e58be83..021d3864 100644
--- a/application/single_app/static/js/chat/chat-messages.js
+++ b/application/single_app/static/js/chat/chat-messages.js
@@ -5117,7 +5117,14 @@ export function appendMessage(
});
}
- scrollChatToBottom();
+ // For AI messages, only auto-scroll if the user is currently near
+ // the bottom. This prevents a final jump after a long answer if
+ // the user has scrolled up to read earlier content.
+ if (typeof isChatNearBottom === 'function' && typeof scrollChatToBottom === 'function') {
+ if (isChatNearBottom()) {
+ scrollChatToBottom();
+ }
+ }
return; // <<< EXIT EARLY FOR AI MESSAGES
// --- Handle ALL OTHER message types ---
@@ -5209,7 +5216,10 @@ export function appendMessage(
// Validate image URL before creating img tag
if (messageContent && messageContent !== 'null' && messageContent.trim() !== '') {
- messageContentHtml = ``;
+ // Use a placeholder container; the actual
element will be
+ // created with DOM APIs after insertion to avoid string-based
+ // attribute interpolation in src/data-*.
+ messageContentHtml = '';
} else {
messageContentHtml = `