兼容 memory-wiki 输入路径并强调相对路径

- memory-wiki 的 wiki_root 路径解析兼容:相对路径 / data/wiki 前缀 / wiki_root 下绝对路径
- 系统提示词强调:模型传相对 wiki 根路径(相对 data/wiki),避免直接给 data/wiki/... 或绝对路径
- 修复并回归:memory-wiki 工具动态加载模块 import-time 错误(sys.modules 注入)
- chat.js 增强会话滚动跟随(异步渲染补滚)

Made-with: Cursor
This commit is contained in:
oliver 2026-04-29 08:54:58 +08:00
parent 27b8698f9b
commit 25180921e7
4 changed files with 100 additions and 11 deletions

View file

@ -2357,16 +2357,30 @@ async function renderChatUi() {
bindChatMermaidViewer(messagesEl);
const AUTO_SCROLL_BOTTOM_GAP_PX = 56;
let shouldFollowMessages = true;
let autoScrollRaf = 0;
let autoScrollTimer = 0;
const isNearBottom = () => {
const remaining = messagesEl.scrollHeight - (messagesEl.scrollTop + messagesEl.clientHeight);
return remaining <= AUTO_SCROLL_BOTTOM_GAP_PX;
};
const scrollMessagesToBottom = (force = false) => {
const scheduleFollowScroll = (force = false) => {
if (!force && !shouldFollowMessages) return;
messagesEl.scrollTop = messagesEl.scrollHeight;
requestAnimationFrame(() => {
if (force || shouldFollowMessages) messagesEl.scrollTop = messagesEl.scrollHeight;
if (autoScrollRaf) cancelAnimationFrame(autoScrollRaf);
if (autoScrollTimer) clearTimeout(autoScrollTimer);
autoScrollRaf = requestAnimationFrame(() => {
messagesEl.scrollTop = messagesEl.scrollHeight;
autoScrollRaf = requestAnimationFrame(() => {
if (force || shouldFollowMessages) messagesEl.scrollTop = messagesEl.scrollHeight;
});
});
// Some async markdown/image/UI post-processing happens after RAF.
autoScrollTimer = setTimeout(() => {
if (force || shouldFollowMessages) messagesEl.scrollTop = messagesEl.scrollHeight;
autoScrollTimer = 0;
}, 60);
};
const scrollMessagesToBottom = (force = false) => {
scheduleFollowScroll(force);
};
messagesEl.addEventListener("scroll", () => {
shouldFollowMessages = isNearBottom();
@ -2380,6 +2394,14 @@ async function renderChatUi() {
},
true,
);
const messagesMutationObserver = new MutationObserver(() => {
scheduleFollowScroll(false);
});
messagesMutationObserver.observe(messagesEl, {
childList: true,
subtree: true,
characterData: true,
});
const textarea = el("textarea", {
class: "chat-composer__field",
rows: "1",