diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-messages.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-messages.ts
index 32ace3aab..c54872b03 100644
--- a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-messages.ts
+++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-messages.ts
@@ -152,6 +152,10 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
@query('.chat-panel-messages')
accessor messagesContainer: HTMLDivElement | null = null;
+ getScrollContainer(): HTMLDivElement | null {
+ return this.messagesContainer;
+ }
+
private _renderAIOnboarding() {
return this.isLoading ||
!this.host?.doc.get(FeatureFlagService).getFlag('enable_ai_onboarding')
@@ -251,7 +255,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
`
: repeat(
filteredItems,
- item => (isChatMessage(item) ? item.id : item.sessionId),
+ (_, index) => index,
(item, index) => {
const isLast = index === filteredItems.length - 1;
return html`
diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts
index fef11066c..96778a330 100644
--- a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts
+++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts
@@ -129,6 +129,8 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
// request counter to track the latest request
private _updateHistoryCounter = 0;
+ private _wheelTriggered = false;
+
private readonly _updateHistory = async () => {
const { doc } = this;
this.isLoading = true;
@@ -261,10 +263,12 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
private _chatContextId: string | null | undefined = null;
private readonly _scrollToEnd = () => {
- this._chatMessages.value?.scrollToEnd();
+ if (!this._wheelTriggered) {
+ this._chatMessages.value?.scrollToEnd();
+ }
};
- private readonly _throttledScrollToEnd = throttle(this._scrollToEnd, 1000);
+ private readonly _throttledScrollToEnd = throttle(this._scrollToEnd, 600);
private readonly _cleanupHistories = async () => {
const notification = this.host.std.getOptional(NotificationProvider);
@@ -324,6 +328,11 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
});
}
+ if (this.chatContextValue.status === 'loading') {
+ // reset the wheel triggered flag when the status is loading
+ this._wheelTriggered = false;
+ }
+
if (
_changedProperties.has('chatContextValue') &&
(this.chatContextValue.status === 'loading' ||
@@ -341,6 +350,19 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
}
}
+ protected override firstUpdated(): void {
+ const chatMessages = this._chatMessages.value;
+ if (chatMessages) {
+ chatMessages.updateComplete
+ .then(() => {
+ chatMessages.getScrollContainer()?.addEventListener('wheel', () => {
+ this._wheelTriggered = true;
+ });
+ })
+ .catch(console.error);
+ }
+ }
+
override connectedCallback() {
super.connectedCallback();
if (!this.doc) throw new Error('doc is required');
diff --git a/packages/frontend/core/src/blocksuite/ai/components/text-renderer.ts b/packages/frontend/core/src/blocksuite/ai/components/text-renderer.ts
index e632a6059..094d7a313 100644
--- a/packages/frontend/core/src/blocksuite/ai/components/text-renderer.ts
+++ b/packages/frontend/core/src/blocksuite/ai/components/text-renderer.ts
@@ -185,6 +185,8 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
private _answers: string[] = [];
+ private _maxContainerHeight = 0;
+
private readonly _clearTimer = () => {
if (this._timer) {
clearInterval(this._timer);
@@ -256,13 +258,6 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
}
};
- private _onWheel(e: MouseEvent) {
- e.stopPropagation();
- if (this.state === 'generating') {
- e.preventDefault();
- }
- }
-
override connectedCallback() {
super.connectedCallback();
this._answers.push(this.answer);
@@ -301,7 +296,7 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
max-height: ${maxHeight ? Math.max(maxHeight, 200) + 'px' : ''};
}
-
+
${keyed(
this._doc,
html`
@@ -328,6 +323,15 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
super.updated(changedProperties);
requestAnimationFrame(() => {
if (!this._container) return;
+ // Track max height during generation
+ if (this.state === 'generating') {
+ this._maxContainerHeight = Math.max(
+ this._maxContainerHeight,
+ this._container.scrollHeight
+ );
+ // Apply min-height to prevent shrinking
+ this._container.style.minHeight = `${this._maxContainerHeight}px`;
+ }
this._container.scrollTop = this._container.scrollHeight;
});
}