diff --git a/.changeset/web-bound-dom-growth.md b/.changeset/web-bound-dom-growth.md new file mode 100644 index 0000000000..927f545728 --- /dev/null +++ b/.changeset/web-bound-dom-growth.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +web: Bound DOM growth in long sessions — tail-biased truncation with expand-to-full for long tool outputs, collapsible tool bodies unmount when closed, tool groups default to collapsed (auto-open while running), and lighter scroll-follow hot paths. diff --git a/apps/kimi-web/src/components/chat/ConversationPane.vue b/apps/kimi-web/src/components/chat/ConversationPane.vue index 1b6b1a9e79..ea78d4f23e 100644 --- a/apps/kimi-web/src/components/chat/ConversationPane.vue +++ b/apps/kimi-web/src/components/chat/ConversationPane.vue @@ -805,7 +805,14 @@ const scrollKey = computed(() => { const thinkingLen = last?.thinking?.length ?? 0; const toolsLen = last?.tools?.reduce( - (n, tool) => n + tool.name.length + (tool.arg?.length ?? 0) + (tool.output?.join('').length ?? 0), + // Track output growth via line count + tail-line length instead of + // joining every tool output on each change. + (n, tool) => + n + + tool.name.length + + (tool.arg?.length ?? 0) + + (tool.output?.length ?? 0) + + (tool.output?.at(-1)?.length ?? 0), 0, ) ?? 0; return { @@ -1126,7 +1133,10 @@ function rebindScrollObservers(): void { updatePanesScrollbarWidth(); if (contentObserver) { contentObserver.disconnect(); - if (el) contentObserver.observe(el, { childList: true, subtree: true, characterData: true }); + // Drop characterData: per-token text updates during streaming fired + // this observer at delta rate; structural changes are enough, and the + // scroll follow is driven by the reactive scrollKey watcher anyway. + if (el) contentObserver.observe(el, { childList: true, subtree: true }); } if (resizeObserver) { resizeObserver.disconnect(); diff --git a/apps/kimi-web/src/components/chat/ToolGroup.vue b/apps/kimi-web/src/components/chat/ToolGroup.vue index 8a30af9bea..4f051814c3 100644 --- a/apps/kimi-web/src/components/chat/ToolGroup.vue +++ b/apps/kimi-web/src/components/chat/ToolGroup.vue @@ -1,6 +1,6 @@ @@ -39,4 +57,20 @@ const outputStyle = { '--tool-output-visible-lines': String(OUTPUT_SCROLL_LINE_C color: var(--color-text-muted); font-style: italic; } +.truncate-toggle { + display: block; + width: 100%; + margin: 0 0 var(--space-2); + padding: var(--space-1) 0; + border: none; + border-bottom: 1px dashed var(--color-line); + background: transparent; + color: var(--color-accent); + font: var(--text-xs) var(--font-ui); + cursor: pointer; + text-align: center; +} +.truncate-toggle:hover { + text-decoration: underline; +} diff --git a/apps/kimi-web/src/i18n/locales/en/tools.ts b/apps/kimi-web/src/i18n/locales/en/tools.ts index 13cc18211f..3148b81917 100644 --- a/apps/kimi-web/src/i18n/locales/en/tools.ts +++ b/apps/kimi-web/src/i18n/locales/en/tools.ts @@ -53,6 +53,9 @@ export default { error: 'failed', done: 'done', }, + output: { + showAll: 'Show all {count} lines', + }, ask: { dismissed: 'Dismissed', answer: '{count} answer', diff --git a/apps/kimi-web/src/i18n/locales/zh/tools.ts b/apps/kimi-web/src/i18n/locales/zh/tools.ts index f9560e3da9..8561299410 100644 --- a/apps/kimi-web/src/i18n/locales/zh/tools.ts +++ b/apps/kimi-web/src/i18n/locales/zh/tools.ts @@ -53,6 +53,9 @@ export default { error: '有失败', done: '已完成', }, + output: { + showAll: '显示全部 {count} 行', + }, ask: { dismissed: '已忽略', answer: '{count} 个回答',