fix: reduce chat debug noise and stabilize auto-scroll behavior
This commit is contained in:
parent
d076e334d9
commit
46404095dd
@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
const ENABLE_APP_DEBUG_LOGS = true;
|
||||
const TRACE_CONV = true;
|
||||
const ENABLE_APP_DEBUG_LOGS = false;
|
||||
const TRACE_CONV = false;
|
||||
|
||||
export function debugLog(...args) {
|
||||
if (!ENABLE_APP_DEBUG_LOGS) return;
|
||||
|
||||
@ -579,7 +579,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
import ToolAction from '@/components/chat/actions/ToolAction.vue';
|
||||
import StackedBlocks from './StackedBlocks.vue';
|
||||
import MinimalBlocks from './MinimalBlocks.vue';
|
||||
@ -695,17 +695,13 @@ const nowMs = ref(Date.now());
|
||||
let timerHandle: number | null = null;
|
||||
const debugLoggedSystemActionKeys = new Set<string>();
|
||||
const debugLoggedUnknownActionKeys = new Set<string>();
|
||||
const CHAT_DEBUG_LOGS = false;
|
||||
const userMDebug = (...args: any[]) => {
|
||||
if (!CHAT_DEBUG_LOGS) {
|
||||
return;
|
||||
}
|
||||
console.log('[USERMDEBUG]', ...args);
|
||||
};
|
||||
const safeJson = (value: any) => {
|
||||
try {
|
||||
return JSON.stringify(value);
|
||||
} catch {
|
||||
return '[unserializable]';
|
||||
}
|
||||
};
|
||||
|
||||
const DEFAULT_GENERATING_TEXT = '生成中…';
|
||||
const rootEl = ref<HTMLElement | null>(null);
|
||||
const thinkingRefs = new Map<string, HTMLElement | null>();
|
||||
@ -898,72 +894,11 @@ function assistantWorkLabel(index: number): string {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
userMDebug('ChatArea.mounted:tail-shape', {
|
||||
filteredLength: filteredMessages.value.length,
|
||||
tail: filteredMessages.value.slice(-8).map((m, i) => ({
|
||||
idx: filteredMessages.value.length - 8 + i,
|
||||
role: m?.role,
|
||||
actionTypes: Array.isArray(m?.actions) ? m.actions.map((a: any) => a?.type) : []
|
||||
}))
|
||||
});
|
||||
timerHandle = window.setInterval(() => {
|
||||
nowMs.value = Date.now();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
watch(
|
||||
filteredMessages,
|
||||
(next) => {
|
||||
const tail = (next || []).slice(-6).map((m: any, i: number) => {
|
||||
const actionTypes = Array.isArray(m?.actions)
|
||||
? m.actions.map((a: any) => `${a?.type}${a?.streaming ? ':streaming' : ''}`)
|
||||
: [];
|
||||
const idx = (next?.length || 0) - Math.min(6, next?.length || 0) + i;
|
||||
return {
|
||||
idx,
|
||||
role: m?.role,
|
||||
actionTypes,
|
||||
isSubAgentNoticeOnlyMessage: isSubAgentNoticeOnlyMessage(m),
|
||||
followedBySubAgentNotice: isFollowedBySubAgentNotice(idx)
|
||||
};
|
||||
});
|
||||
userMDebug('ChatArea.watch:filteredMessages-changed', {
|
||||
length: next?.length || 0,
|
||||
tail
|
||||
});
|
||||
userMDebug('ChatArea.watch:filteredMessages-changed:json', safeJson({
|
||||
length: next?.length || 0,
|
||||
tail
|
||||
}));
|
||||
|
||||
nextTick(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const root = rootEl.value;
|
||||
if (!root) return;
|
||||
const blocks = Array.from(root.querySelectorAll('.message-block')) as HTMLElement[];
|
||||
const last = blocks.slice(-4);
|
||||
const geometry = last.map((el, i) => {
|
||||
const r = el.getBoundingClientRect();
|
||||
const prev = i > 0 ? last[i - 1].getBoundingClientRect() : null;
|
||||
const gapFromPrev = prev ? Math.round((r.top - prev.bottom) * 100) / 100 : null;
|
||||
return {
|
||||
className: el.className,
|
||||
top: Math.round(r.top * 100) / 100,
|
||||
bottom: Math.round(r.bottom * 100) / 100,
|
||||
height: Math.round(r.height * 100) / 100,
|
||||
gapFromPrev
|
||||
};
|
||||
});
|
||||
userMDebug('ChatArea.layout:last-blocks', {
|
||||
totalBlocks: blocks.length,
|
||||
geometry
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (timerHandle !== null) {
|
||||
clearInterval(timerHandle);
|
||||
@ -988,7 +923,7 @@ const splitActionGroups = (actions: any[] = [], messageIndex = 0) => {
|
||||
let buffer: any[] = [];
|
||||
|
||||
// 调试:记录输入
|
||||
if (actions.length > 0) {
|
||||
if (CHAT_DEBUG_LOGS && actions.length > 0) {
|
||||
console.log(`[splitActionGroups] 消息 ${messageIndex}:`, {
|
||||
totalActions: actions.length,
|
||||
actionTypes: actions.map((a) => a.type),
|
||||
@ -1034,7 +969,7 @@ const splitActionGroups = (actions: any[] = [], messageIndex = 0) => {
|
||||
flushBuffer();
|
||||
|
||||
// 调试:记录输出
|
||||
if (actions.length > 0) {
|
||||
if (CHAT_DEBUG_LOGS && actions.length > 0) {
|
||||
console.log(`[splitActionGroups] 消息 ${messageIndex} 结果:`, {
|
||||
totalGroups: result.length,
|
||||
groups: result.map((g) => ({
|
||||
|
||||
@ -27,31 +27,45 @@ type ScrollOptions = {
|
||||
behavior?: ScrollBehavior;
|
||||
};
|
||||
|
||||
type PendingScrollTask = {
|
||||
rafId: number | null;
|
||||
settleTimer: ReturnType<typeof setTimeout> | null;
|
||||
};
|
||||
|
||||
const pendingScrollTasks = new WeakMap<HTMLElement, PendingScrollTask>();
|
||||
let autoScrollRafId: number | null = null;
|
||||
|
||||
export function scrollToBottom(ctx: ScrollContext, options?: ScrollOptions) {
|
||||
const messagesArea = ctx.getMessagesAreaElement?.();
|
||||
if (!messagesArea) {
|
||||
return;
|
||||
}
|
||||
|
||||
const attempts = [0, 16, 60, 150, 320, 520]; // 多次尝试覆盖布局抖动/异步伸缩
|
||||
let cancelled = false;
|
||||
const useSmooth =
|
||||
options?.behavior === 'smooth' && typeof (messagesArea as HTMLElement).scrollTo === 'function';
|
||||
|
||||
const perform = (idx: number) => {
|
||||
if (cancelled) return;
|
||||
let task = pendingScrollTasks.get(messagesArea);
|
||||
if (!task) {
|
||||
task = { rafId: null, settleTimer: null };
|
||||
pendingScrollTasks.set(messagesArea, task);
|
||||
}
|
||||
if (task.rafId !== null) {
|
||||
cancelAnimationFrame(task.rafId);
|
||||
task.rafId = null;
|
||||
}
|
||||
if (task.settleTimer) {
|
||||
clearTimeout(task.settleTimer);
|
||||
task.settleTimer = null;
|
||||
}
|
||||
|
||||
const perform = () => {
|
||||
if (ctx.userScrolling && !options?.ignoreUserScrolling) {
|
||||
cancelled = true;
|
||||
if (typeof ctx._setScrollingFlag === 'function') {
|
||||
ctx._setScrollingFlag(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx === 0 && typeof ctx._setScrollingFlag === 'function') {
|
||||
ctx._setScrollingFlag(true);
|
||||
}
|
||||
|
||||
if (useSmooth) {
|
||||
(messagesArea as HTMLElement).scrollTo({
|
||||
top: messagesArea.scrollHeight,
|
||||
@ -61,10 +75,12 @@ export function scrollToBottom(ctx: ScrollContext, options?: ScrollOptions) {
|
||||
messagesArea.scrollTop = messagesArea.scrollHeight;
|
||||
}
|
||||
|
||||
if (idx < attempts.length - 1) {
|
||||
setTimeout(() => perform(idx + 1), attempts[idx + 1] - attempts[idx]);
|
||||
} else if (typeof ctx._setScrollingFlag === 'function') {
|
||||
setTimeout(() => ctx._setScrollingFlag && ctx._setScrollingFlag(false), 40);
|
||||
task!.settleTimer = setTimeout(() => {
|
||||
// 补一次,覆盖图片/折叠动画等异步高度变化
|
||||
messagesArea.scrollTop = messagesArea.scrollHeight;
|
||||
if (typeof ctx._setScrollingFlag === 'function') {
|
||||
ctx._setScrollingFlag(false);
|
||||
}
|
||||
if (options?.resetUserScrolling) {
|
||||
if (typeof ctx.chatSetScrollState === 'function') {
|
||||
ctx.chatSetScrollState({ userScrolling: false });
|
||||
@ -72,22 +88,33 @@ export function scrollToBottom(ctx: ScrollContext, options?: ScrollOptions) {
|
||||
ctx.userScrolling = false;
|
||||
}
|
||||
}
|
||||
} else if (options?.resetUserScrolling) {
|
||||
if (typeof ctx.chatSetScrollState === 'function') {
|
||||
ctx.chatSetScrollState({ userScrolling: false });
|
||||
} else if ('userScrolling' in ctx) {
|
||||
ctx.userScrolling = false;
|
||||
}
|
||||
}
|
||||
task!.settleTimer = null;
|
||||
}, 120);
|
||||
};
|
||||
|
||||
perform(0);
|
||||
if (typeof ctx._setScrollingFlag === 'function') {
|
||||
ctx._setScrollingFlag(true);
|
||||
}
|
||||
|
||||
task.rafId = requestAnimationFrame(() => {
|
||||
task!.rafId = null;
|
||||
perform();
|
||||
if (!task!.settleTimer && typeof ctx._setScrollingFlag === 'function') {
|
||||
ctx._setScrollingFlag(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function conditionalScrollToBottom(ctx: ScrollContext) {
|
||||
const active = typeof ctx.isOutputActive === 'function' ? ctx.isOutputActive() : true;
|
||||
if (ctx.autoScrollEnabled === true && ctx.userScrolling === false && active) {
|
||||
scrollToBottom(ctx);
|
||||
if (autoScrollRafId !== null) {
|
||||
cancelAnimationFrame(autoScrollRafId);
|
||||
}
|
||||
autoScrollRafId = requestAnimationFrame(() => {
|
||||
autoScrollRafId = null;
|
||||
scrollToBottom(ctx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,14 +20,14 @@ const monitorTrace = (label: string) => {
|
||||
}
|
||||
console.trace(`[Monitor] ${label}`);
|
||||
};
|
||||
const MONITOR_PROGRESS_DEBUG = true;
|
||||
const MONITOR_PROGRESS_DEBUG = false;
|
||||
const monitorProgressDebug = (...args: any[]) => {
|
||||
if (!MONITOR_PROGRESS_DEBUG) {
|
||||
return;
|
||||
}
|
||||
console.debug('[MonitorProgressStore]', ...args);
|
||||
};
|
||||
const MONITOR_LIFECYCLE_DEBUG = true;
|
||||
const MONITOR_LIFECYCLE_DEBUG = false;
|
||||
const monitorLifecycleLog = (...args: any[]) => {
|
||||
if (!MONITOR_LIFECYCLE_DEBUG) {
|
||||
return;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user